💡 자바스크립트를 좀 더 알아보자
비동기에 대해서는 어느정도 알고가자
💡 ES6에서 등장한 문법으로써, 배열이나 객체 속성을 해체하여 개별 변수에 값을 담을 수 있는 JavaScript 표현식을 말합니다.
또는 구조 분해 할당이라고 명칭 합니다.
💡 배열, 객체 내 값을 추출하는 코드가 매우 간단해진다.
필요한 객체와 나머지 요소 분리가 매우 간단하다.
기본값 지정이 가능하다.
만약, object가 다음과 같이 생겼다면, 프로퍼티(key값)을 변수로 선언해 바로 해당 object의 값을 이용할 수 있습니다.
const object = { a: 1, b: 2 };
const { a, b } = object;
/*
얘와 같아요
const a = object.a; // 하위 속성이 있을 때 쓸 수 있습니다
const b = object.b;
*/
console.log(a); // 1
console.log(b); // 2
함수에서도 가능합니다.
const object = { a: 1, b: 2 };
function print({ a, b }) {
console.log(a);
console.log(b);
}
print(object);
// 이렇게 쓰면 좋은점
function Example(a, b, c) {
...
}
Example(a=1, b=2, c=3) // 이렇게 순서를 맞춰 넣어줘야하는데
function Example({a, b, c}) {
...
}
Example({a:1, c:3, b:2}) // key 이름만 맞춰주면 된다~
변수의 이름도 바꿀 수 있어요
const animal = {
name: '멍멍이',
type: '개'
};
const { name: nickname } = animal // animal의 name이라는 속성을 nickname으로 쓸꺼야
console.log(nickname); // '멍멍이'
배열도 됩니다
const array = [1, 2];
const [one, two] = array;
console.log(one);
console.log(two);
만약 내가 지정한 변수보다 넣어줄 매칭 할 값이 없다면 undefined가 발생한다.
만약 이때 undefined가 아니라 기본적으로 넣어주는 값이 있다고 하면 기본 값 을지 정하는 것도 가능하다.
const fruit = ['Apple', 'Banana', 'Peach'];
const [Apple,Banana, Peach, Pear='Pear'] = fruit;
console.log(Apple);
console.log(Banana);
console.log(Peach);
console.log(Pear);
번외
const extracted = {
name: name,
languages: languages,
value: value
}
이 코드와
const extracted = {
name,
languages,
value
}
이 코드는 같은 의미입니다
객체는 { 속성명 : 값 } 으로 이루어져 있는 것을 다들 아실텐데,
속성명과 값의 이름이 같다면 : 를 생략할 수 있습니다!
for문이랑 비슷합니다
const superheroes = ['아이언맨', '캡틴 아메리카', '토르', '닥터 스트레인지'];
for (let i = 0; i < superheroes.length; i++) {
console.log(superheroes[i]);
}
superheroes.forEach((hero, index, arr) => {
console.log(hero, index, arr);
});
배열 안의 각 원소를 변환 할 때 사용 되며, 이 과정에서 새로운 배열이 만들어집니다.
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const squared = [];
for (let i = 0; i < array.length; i++) {
squared.push(array[i] * array[i]);
}
const squaredMap = array.map((item) => item * item);
console.log(squared. squaredMap);
원하는 항목이 몇번째 원소인지 찾아주는 함수입니다.
const superheroes = ['아이언맨', '캡틴 아메리카', '토르', '닥터 스트레인지'];
const index = superheroes.indexOf('토르');
console.log(index); // 2
배열의 원소중, 조건을 만족하는 원소의 index를 리턴 해줍니다
const todos = [
{
id: 1,
text: '자바스크립트 입문',
done: true
},
{
id: 2,
text: '함수 배우기',
done: true
},
{
id: 3,
text: '객체와 배열 배우기',
done: true
},
{
id: 4,
text: '배열 내장함수 배우기',
done: false
}
];
const index = todos.findIndex(todo => todo.id === 3);
console.log(index);
// 결과가 여러개인 경우 가장 빠른 원소의 index를 리턴
배열에서 특정 조건을 만족하는 값들만 따로 추출하여 새로운 배열을 만듭니다.
const todos = [
{
id: 1,
text: '자바스크립트 입문',
done: true
},
{
id: 2,
text: '함수 배우기',
done: true
},
{
id: 3,
text: '객체와 배열 배우기',
done: true
},
{
id: 4,
text: '배열 내장함수 배우기',
done: false
}
];
const tasksNotDone = todos.filter(todo => todo.done === false);
console.log(tasksNotDone);
배열에서 특정 항목을 제거할 때 사용합니다
첫번째 파라미터는 어떤 인덱스부터 지울지를 의미하고 두번째 파라미터는 그 인덱스부터 몇개를 지울지를 의미합니다.
const numbers = [10, 20, 30, 40];
const index = numbers.indexOf(30);
numbers.splice(index, 1);
console.log(numbers); // [10, 20, 40]
배열 안의 값들을 문자열 형태로 합쳐줍니다.
const array = [1, 2, 3, 4, 5];
console.log(array.join()); // 1,2,3,4,5
console.log(array.join(' ')); // 1 2 3 4 5
console.log(array.join(', ')); // 1, 2, 3, 4, 5
연산의 결과를 누적하여 최종 값을 반환합니다.
const numbers = [1, 2, 3, 4, 5];
const sum = array.reduce((accumulator, current, index, arr) => accumulator + current, 0);
console.log(sum);
콘솔을 이용해 단계 별 값을 봐봅시다
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current, index, arr) => {
console.log({ accumulator, current, index, arr });
return accumulator + current;
}, 0);
console.log(sum);
💡 요청을 보낸 후 응답을 받아야 다음 태스크가 수행되는 것
응답 받기 전 까지 이후 태스크들은 블로킹된다.
💡 병렬적으로 처리한다.
태스크가 종료되지 않은 상태여도 대기하지 않고 다음 태스크를 실행한다.
대부분의 DOM이벤트 핸들러와 Timer함수, api요청은 비동기로 처리한다.
1 → 3 → (1초 후) 2
결과값은 “1”, “3”, “2” 순으로 찍혔다.
이는 setTimeout()메소드가 비동기적 API이기 때문이다.
위의 코드를 컴퓨터의 입장에서 해석해보면 다음과 같다.
따라서...
동기
는 디자인이 비동기
보다 간단하고 직관적일수 있지만 결과가 주어질 때 까지 아무것도 못하고 대기해야하는 문제가 있다.
비동기
는 동기
보다 복잡하지만 결과가 주어지는데 시간이 걸려도 그 시간동안 다른 작업을 할 수 있어서 보다 효율적일 수 있다.
참고자료
https://velog.io/@daybreak/Javascript-비동기-처리
💡 JavaScript에서 서버로 HTTP 요청을 보내고 응답을 받을 수 있도록 해주는 함수이다.
그렇기 때문에 기본적인 구조와 동작은 Promise 객체와 동일합니다. (Promise는 바로 다음에 배웁니다^^)
파라미터로 요청을 보낼 url을 입력해 주고 응답을 받아서 추가적인 작업 또한 해줄 수 있습니다.
then에서 응답 객체를 받고, catch에서 에러 요청이 발생했을 때, 에러 객체를 받습니다.
HTTP 요청을 기반으로 하기 때문에 HTTP 메서드를 이용할 수 있습니다.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) =>
console.log(response)
);
응답 객체는 다음과 같습니다
Response {
status: 200,
ok: true,
redirected: false,
type: "cors",
url: "https://jsonplaceholder.typicode.com/posts/1",
…
}
→ 이건 응답 전체에 대한 정보
대부분의 REST API들은 JSON 형태의 데이터를 응답하기 때문에, 응답(response) 객체는 json()
메서드를 제공합니다.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((response) => response.**json()**)
.then((data) => console.log(data));
이 메서드를 호출하면, 응답(response) 객체로 부터 JSON 포멧의 응답을 자바스크립트 객체로 변환하여 얻을 수 있습니다.
json() Response 스트림을 가져와 스트림이 완료될때까지 읽는다. 그리고 다 읽은 body의 텍스트를 Promise형태로 반환합니다.
받은 데이터는 다음과 같습니다.
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit↵suscipit recusandae consequuntur …strum rerum est autem sunt rem eveniet architecto"
}
fetch("https://jsonplaceholder.typicode.com/posts", {
**method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Test",
body: "I am testing!",
userId: 1,
}),**
})
.then((response) => response.json())
.then((data) => console.log(data));
새로운 포스트 생성 위해서는 method를 POST로 지정해주고,
headers에는 JSON 포맷 사용한다고 알려줘야 합니다.
body에는 요청 전문을 JSON 포멧으로 넣어주세요.
결과는 다음과 같습니다.
fetch("https://jsonplaceholder.typicode.com/posts/1", {
method: **"PUT",**
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Test",
body: "I am testing!",
userId: 1,
}),
})
.then((response) => response.json())
.then((data) => console.log(data));
결과는 다음과 같습니다
→ 업데이트 된 결과
fetch("https://jsonplaceholder.typicode.com/posts/1", {
method: "DELETE",
})
.then((response) => response.json())
.then((data) => console.log(data));
→ 데이터가 없는 이유는?
→ 삭제를 했으니 성공이라는 status 말곤 돌려줄 데이터가 없기 때문
💡 프로미스는 자바스크립트 비동기 처리에 사용되는 객체입니다.
여기서 자바스크립트의 비동기 처리란
‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’을 의미합니다
api 호출을 하는 코드를 봐봅시다
// api를 호출하는 함수를 선언, 파라미터로 함수를 필요로함
function getData(callbackFunc) {
// 밑의 줄이 실행되면 api 호출 이후, 파라미터로 받은 함수가 실행됨
$.get('url 주소', function(response) {
// 서버에서 받은 데이터 response를 파라미터로 받은 함수에 인자로 넘겨줌
callbackFunc(response);
});
}
//해당 함수를 호출
getData(function innerFun(tableData) { //파라미터로 함수를 전달함
console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});
getData() 를 정의하고 파라미터로 callbackFunc을 받는다.
api 요청이 성공하면 서버에서 받은 데이터인 response를
파라미터인 callbackFunc의 파라미터로 전달해서 실행한다.
이런 느낌
위 코드에 Promise를 적용하면 다음과 같이 변한다.
// Promise 객체를 생성하여 반환하는 함수
function getData(callback) {
return new Promise(function(resolve) {
$.get('url 주소', function(response) {
resolve(response); //성공을 반환
});
});
}
// getData()의 실행이 성공하면 then()이 호출됨
getData().then(function(tableData) {
// resolve()의 결과 값이 여기로 전달됨
console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});
getData()가 실행되면 Promise 객체를 반환하게 한다.
getData()를 호출하는 곳에서 성공적으로 반환되면 .then()을 통해 로직을 실행한다.
then() 에서 성공 후 로직을 살행한다
어렵죠?
저도 어렵습니다^^
본격적으로 파해치기 전에 프로미스의 3가지 상태에 대해 알아보자
new Promise(function(resolve, reject) {
// ...
});
new Promise(function(resolve, reject) {
resolve();
});
function getData() {
return new Promise(function(resolve, reject) {
const data = 100;
resolve(data); //data를 성공적으로 반환
});
}
// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
console.log(resolvedData); // 100
});
→ 밑에 나오는 Promise는 getData() 함수의 반환값입니다.
→ getData() 함수는 return new Promise ~ 로 알 수 있듯이 Promise 객체를 반환하기 때문에 반환값이 존재합니다
new Promise(function(resolve, reject) {
reject();
});
function getData() {
return new Promise(function(resolve, reject) {
reject("Request is failed"); //에러를 발생시키는 것
});
}
// reject()의 결과 값을 err에 받음
getData().catch(function(err) {
console.log(err); // Request is failed
});
fulfilled인 이유는 getData()가 실행된 것이 콘솔에 출력되어서 그렇다!
다음과 같이 여러 개의 Promise를 연결하여 사용할 수 있다.
new Promise(function(resolve, reject){
setTimeout(function() {
resolve(1);
}, 2000); //2초 뒤에 실행
})
.then(function(result) {
console.log(result); // result는?
return result + 10;
})
.then(function(result) {
console.log(result); // result는?
return result + 20;
})
.then(function(result) {
console.log(result); // result는?
});
catch 이후 then도 가능하다
new Promise((resolve, reject) => {
throw new Error("에러 발생!");
}).catch(function(error) {
alert("에러가 잘 처리되었습니다. 정상적으로 실행이 이어집니다.");
}).then(() => alert("다음 핸들러가 실행됩니다."));
프로미스 처리 흐름 - 출처 : MDN
5분 짜리 실습
콘솔에 찍어보고 위 내용을 이해해보세요~
function getPromise() {
return new Promise(function (resolve, reject){
setTimeout(() => resolve(123),5000);
})
}
console.log(getPromise());
5초안에 콘솔을 열어야 pending으로 보임
function getPromise() {
return new Promise(function (resolve, reject){
resolve(123)
})
}
console.log(getPromise());
function getPromise() {
return new Promise(function (resolve, reject){
reject(123)
})
}
console.log(getPromise());
💡 async와 await는 자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법.
기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.
fetchUser()가 api요청을 한다고 가정했을 때
function logName() {
var user = fetchUser('domain.com/users/1', function(user) {
if (user.id === 1) {
console.log(user.name);
}
});
}
→ fetchUser라는 함수의 2번째 인자로 어떤 함수가 들어갔다.
ㄴ> 이것은 요청 후, 바로 저 함수를 실행하라는 의미 (이것을 콜백함수라고 함)
바로 알아보기가 힘들죠?
async function logName() { // 이건 비동기 함수야
const user = **await** fetchUser('domain.com/users/1'); //응답을 기다릴꺼야
/* user === { id: 1, name: John } 라 가정한다면*/
if (user.id === 1) {
console.log(user.name);
}
}
function fetchItems() { // 4
return new Promise(function(resolve, reject) {
const items = [1,2,3]; // 5
resolve(items) // 6
});
}
async function logItems() { // 2
const resultItems = await fetchItems(); // 3
console.log(resultItems); // [1,2,3] // 7
}
logItems(); // 1
방금 전 Promise를 배웠으니 알아보겠죠..? 아님말고
promise에서 배운 것 처럼 catch를 이용하면 됩니다 (근데 살짝 다름)
async
함수에서 에러를 발생 시킬때에는 **throw**
를 사용하고, 에러를 잡아낼 때에는 try/catch
문을 사용합니다.
async function logTodoTitle() {
try { //시도해라
const user = await fetchUser();
if (user.id === 1) {
var todo = await fetchTodo();
console.log(todo.title); // delectus aut autem
}
} catch (error) { //에러 발생시 여기로
console.log(error);
}
}
////////////////////////////////////////////
async function process() {
try {
throw new Error('에러 발생');
} catch (e) {
console.error(e+'123123');
}
}
process();
해당 url에 요청을 보내 응답값을 반환하는 함수를 만들고 (fetch 이용)
해당 함수를 호출해 반환한 응답값을 콘솔에 찍어주세요
p.s. json()도 비동기입니다!
function fetchUser() {
const url = 'https://jsonplaceholder.typicode.com/users/1';
}
//
fetchUser().
💡 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)인데,
이는 여러분이 원한다면 그것들에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주는 것
⇒ 한 마디로 말하자면 시스템에서 발생하는 것
💡 DOM과 관련된 이벤트가 발생하면 관련 정보는 모두 event객체에 저장됩니다.
이벤트 발생 요소, 이벤트 타입, 이벤트 관련 데이터도 저장됩니다.
ex) 마우스 이벤트 -> 마우스의 위치정보 포함 등키보드 이벤트 -> 누른 키의 코드 등
💡 실제 이벤트가 발생하는 요소
💡 이벤트 리스너가 달린 요소
💡 이벤트에 대해 대기중인 것
⇒ 이벤트를 감지하고 있다~
click, onchange, keyup, keydown 등등..
// 윈도우 자체에 이벤트를 등록하거나
window.addEventListener('click', function() {});
// html element에도 등록할 수 있습니다
const button = document.querySelector('{클래스 이름}');
button.addEventListener('click', function() {});
💡 자식부터 부모로 쭉 이벤트가 전파되는 것.
<body>
<div
class="one"
style="width: 200px; height: 200px; background-color: antiquewhite"
>
<div
class="two"
style="width: 150px; height: 150px; background-color: azure"
>
<div
class="three"
style="width: 100px; height: 100px; background-color: cadetblue"
></div>
</div>
</div>
<script>
//div 태그를 전부 가져와 divs라는 이름에 배열로 할당한다.
const divs = document.querySelectorAll("div");
//divs의 길이만큼 반복하여 각 태그에 이벤트를 할당해준다.
for (let i=0; i<divs.length; i++) {
divs[i].addEventListener('click', logEvent);
}
// event 객체를 파라미터(인자) 로 받아
// **이벤트 객체**의 **이벤트가 달린 요소**의 **클래스 이름**을 출력해준다
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
</body>
three를 클릭했을 때
각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있습니다. 만약 이벤트가 특정 div 태그에만 달려 있다면 위와 같은 동작 결과는 확인할 수 없습니다.
이와 같은 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링(Event Bubbling)이라고 합니다.
위 코드의 logEvent함수 안에서 event.currentTarget.className이 아닌 event.target.className으로 바꾼다면 어떻게 출력될까요?
💡 부모부터 자식까지 이벤트가 전파되는 것.
<body>
<div
class="one"
style="width: 200px; height: 200px; background-color: antiquewhite"
>
<div
class="two"
style="width: 150px; height: 150px; background-color: azure"
>
<div
class="three"
style="width: 100px; height: 100px; background-color: cadetblue"
></div>
</div>
</div>
<script>
const divs = document.querySelectorAll("div");
for (let i=0; i<divs.length; i++) {
divs[i].addEventListener('click', logEvent, {
capture: true, // default 값은 false입니다.
});
}
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
</body>
three를 클릭했을 때
→ “난 이렇게 복잡한 이벤트 전달 방식 알고 싶지 않고, 그냥 원하는 화면 요소의 이벤트만 신경 쓰고 싶어요.”
이렇게 사용합니다
function logEvent(event) {
event.stopPropagation();
}
// 이벤트 버블링 예제
for (let i=0; i<divs.length; i++) {
divs[i].addEventListener('click', logEvent);
}
function logEvent(event) {
event.stopPropagation(); //이벤트가 전파되는것을 막아라!
// 클릭한 곳의 클래스명만 출력됩니다
console.log(event.currentTarget.className);
}
// 이벤트 캡쳐링 예제
for (let i=0; i<divs.length; i++) {
divs[i].addEventListener('click', logEvent, {
capture: true, // default 값은 false입니다.
});
}
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className);
// 어떤 결과가 예상되는지 채팅창에 적어주세요
}
/* 어딜 클릭하던 one이 찍힘 -> 맨 상위부터 시작이니까 */
spread 라는 단어가 가지고 있는 의미는 펼치다, 퍼뜨리다 입니다.
이 문법을 사용하면, 객체 혹은 배열을 펼칠수있습니다.
예를 들어서 다음과 같은 객체들이 있다고 가정해봅시다.
const slime = {
name: '슬라임'
};
const cuteSlime = {
name: '슬라임',
attribute: 'cute'
};
const purpleCuteSlime = {
name: '슬라임',
attribute: 'cute',
color: 'purple'
};
console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);
cuteSlime엔 slime에 있는 속성이 존재하고
purpleCuteSlime엔 cureSlime에 있는 속성들이 존재합니다.
spread 문법을 이용하면 기존 형태에 원하는 속성만 추가 할 수 있습니다.
const slime = {
name: '슬라임'
};
const cuteSlime = {
...slime,
attribute: 'cute'
};
const purpleCuteSlime = {
...cuteSlime,
color: 'purple'
};
const purpleAwesomeSlime = {
...cuteSlime,
attribute : 'Awesome', //기존 속성이 중복되면 기존 속성을 대체합니다.
color: 'purple'
};
console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);
console.log(purpleAwesomeSlime);
→ 같은 결과가 나옵니다.
마찬가지로 배열에서도 사용할 수 있습니다
const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
// animals값을 가져오고 '비둘기' 값을 추가 해줍니다.
console.log(animals);
console.log(anotherAnimals);
spread 연산자를 여러번 사용 할 수도 있습니다.
const numbers = [1, 2, 3, 4, 5];
const spreadNumbers = [...numbers, 1000, ...numbers];
console.log(spreadNumbers); // [1, 2, 3, 4, 5, 1000, 1, 2, 3, 4, 5]
💡 말 그대로 나머지 속성을 가져옵니다.
const purpleCuteSlime = {
name: '슬라임',
attribute: 'cute',
color: 'purple'
};
const { color, ...rest } = purpleCuteSlime;
// 처음에 봤던 구조 분해 할당으로써
// purpleCuteSlime.color 와 나머지 속성들을 할당합니다
console.log(color);
console.log(rest);
→ 원하는 이름으로 해도 됩니다.
const purpleCuteSlime = {
name: '슬라임',
attribute: 'cute',
color: 'purple'
};
const { color, ...cuteSlime } = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);
const numbers = [0, 1, 2, 3, 4, 5, 6];
const [one, ...rest] = numbers;
console.log(one); // 0
console.log(rest); // [1,2,3,4,5,6]
반대는 안되나요?
const numbers = [0, 1, 2, 3, 4, 5, 6];
const [..rest, last] = numbers;
→ 안됩니다~
// 어떤 파라미터들이 들어올지 모를때 사용합니다
// 들어온 값들을 모두 더한 결과를 반환해주는 함수
function sum(...rest) {
//rest === [1, 2, 3, 4, 5, 6]
return rest.reduce((acc, current) => acc + current, 0);
}
const result = sum(1, 2, 3, 4, 5, 6);
console.log(result); // 21
spread와 같이 사용할 수도 있습니다.
function sum(...rest) {
return rest.reduce((acc, current) => acc + current, 0);
}
const numbers = [1, 2, 3, 4, 5, 6];
const result = sum(...numbers);
console.log(result);
실습
함수에 n 개의 숫자들이 파라미터로 주어졌을 때, 그 중 가장 큰 값을 알아내세요.
function max() {
return 0;
}
const result = max(1, 2, 3, 4, 10, 5, 6, 7);
console.log(result);
💡 우리가 변수 혹은 함수를 선언하게 될 때 해당 변수 또는 함수가 유효한 범위를 의미
const value = 'hello!';
function myFunction() {
console.log('myFunction: ');
console.log(value);
}
function otherFunction() {
console.log('otherFunction: ');
const value = 'bye!';
console.log(value);
}
myFunction();
otherFunction();
console.log('global scope: ');
console.log(value);
→ 이렇게 같은 이름을 가진 변수를 설정한다고 해서 기존에 Global Scope 로 선언된 value
변수의 값이 바뀌지 않습니다.
const value = 'hello!';
function myFunction() {
const value = 'bye!'; //블록 스코프이자 함수 스코프를 가짐
const anotherValue = 'world'; //블록 스코프이자 함수 스코프를 가짐
function functionInside() {
console.log('functionInside: ');
console.log(value);
console.log(anotherValue);
}
functionInside();
}
myFunction();
console.log('global scope: ');
console.log(value);
console.log(anotherValue);