이번 시간은 scope 라는 개념을 배워보겠습니다.
scope은 JavaScript의 문법이 아닙니다.
JavaScript에서 scope이란, '변수가 어디까지 쓰일 수 있는지'의 범위를 의미합니다.
is not defined
라는 에러 메시지를 보셨나요?
변수가 아직 선언되지 않았다는 뜻입니다.
"아닌데! 변수는 let, const, var 등으로 선언할 수 있고, 나는 분명 선언했는데!" 하시겠지만 변수를 선언한 영역에(block에) 접근할 수가 없어서 컴퓨터가 변수가 선언 되었다는 사실을 알지 못해서 그랬을것입니다.
그래서 변수가 선언되지 않았다는 오류메시지를 출력하게 되는 것입니다. 어떤 변수는 여기저기서 쓸 수 있는 반면에, 어떤 변수는 특정 함수 내에서만 쓸 수 있었습니다.
이런 개념이 바로 scope입니다.
scope을 더 파헤치기 전에 먼저 알아야할 개념은 block입니다.
그 동안에 function
과 if
문, for
문을 하면서 이미 block을 많이 경험했습니다.
block이란 중괄호({}
, curly brace)로 감싸진 것을 block이라고 합니다.
function
의 내부는 하나의 block입니다.
function hi() {
return 'i am block';
}
for
문도 하나의 block이고요
for (let i = 0; i < 10; i++) {
count++;
}
if
문의 {}
도 하나의 block입니다.
if (i === 1) {
let j = 'one';
console.log(j);
}
{}
(block)내부에서 변수가 정의되면 변수는 오로지 {}
(block)내부에서만 사용할 수 있습니다.
{}
(block)내부에서 정의된 변수는 local(지역) 변수라고 부릅니다.
아래의 코드는 문제가 있습니다. 그 동안 Assignment 하면서 한 번이라도 겪었던 문제 아닌가요?
function getResult() {
let result = 10;
return result;
}
// 자바스크립트 에러!
// getResult 내부의 scope에 접근할 수 없다
console.log(result);
console.log(result)
에서 getResult
내부에 접근이 불가능하기 때문에 result
라는 변수의 존재를 알지 못합니다.
result
라는 변수는 getResult
함수의 {}
(block)에서만 사용할 수 있습니다.
console.log(result);
를 주석처리해서 일단 오류를 제거해주세요.
scope은 변수가 선언되고 사용할 수 있는 공간입니다.
scope 외부(block밖)에서는 특정 scope의 변수에 접근할 수가 없습니다.
block밖인 global scope에서 만든 변수를 global variable(전역변수)라고 합니다.
코드 어디서든 접근 가능해서 변수값을 확인할 수 있습니다.
const color = 'red';
console.log(color);
function returnColor() {
console.log(color);
return color;
}
console.log(returnColor());
returnColor
함수 내에서, returnColor
함수 밖에 있는 color
라는 변수를 return 해주었습니다.
color
라는 변수는 global 변수이기 때문에 returnColor
함수의 block에서도 접근이 가능해서 'red'
를 반환한것입니다.
global 변수를 쓰면 여기 저기서 접근하기 쉬워서 좋다고 생각할 수 있지만, 너무 남용하면 프로그램에 문제를 일으킬 수 있습니다.
global 변수를 선언하면, 해당프로그램의 어디에서나 사용할 수 있는 global namespace를 갖습니다.
namespace라는 것은 변수 이름을 사용할 수 있는 범위라는 뜻입니다. scope이라고도 하고 특히 변수이름을 얘기할 때는 namespace라고도 합니다.
global 변수는 프로그램이 종료될때까지 계속 살아있습니다. 이 말은 local 변수는 {} - block이 끝나면 더 이상 변수가 살아있지 않고 쓸 수 없다는 말입니다.
global 변수가 계속 살아있어서 변수값이 계속 변한다면 해당 변수를 트래킹하기도 어렵고 이 변수는 어디에서 왜 필요한지 알려면 도대체 어디에서 let
, const
로 선언을 했는지 찾아 나서야 합니다.
아래는 scope이 오염된 대표적인 예입니다.
const satellite = 'The Moon';
const galaxy = 'The Milky Way';
let stars = 'North Star';
const callMyNightSky = () => {
stars = 'Sirius';
return 'Night Sky: ' + satellite + ', ' + stars + ', ' + galaxy;
};
console.log(callMyNightSky());
console.log(stars);
stars
이라는 global 변수가 있습니다.callMyNightSky
함수에서 새로운 변수를 선언하고 싶었는데 깜빡하고 let
키워드를 작성하지 않았습니다.callMyNightSky
을 호출하면 stars 변수에 "Sirius"
이 할당됩니다.stars
에 영향이 갔습니다!stars
을 사용하고 싶은데 값이 수정된 "Sirius"
으로 사용하게 됩니다.앞으로 함수가 몇 십개 있을지도 모르는 상황에서 저렇게 global 변수를 남용 하다가는 어디서 어떻게 값이 수정될지 알 수 없어집니다.
위와 같이 global 변수가 여기저기서 수정되면 안되기 때문에 변수들은 block scope으로 최대한 나눠놔야 합니다.
즉, 한마디로 요약하면 global 변수는 쓰지 않도록 노력해야 하고, 최대한 {}
내에서 let
, const
을 사용하여 변수를 새로 만들어서 쓰자는 말입니다.
이제 마지막 예제입니다!
이번에는 if
문의 {}
의 block scope을 보겠습니다.
function logSkyColor() {
const dusk = true;
let myColor = 'blue';
if (dusk) {
let myColor = 'pink';
console.log(myColor); // pink
}
console.log(myColor); // blue
}
console.log(myColor); // 에러!!
if
문에 {}
의 코드 block을 사용하였습니다. 여기에 myColor
라는 변수를 let
으로 선언하였습니다.if
문 내에서는 "pink"
라고 할당 하였고, if
문 밖에서는 "blue"
라고 할당한 것에 주목해주세요.사실 이 코드는 function
의 block, scope, if
문의 block, scope으로, 모두 block 을 잘 사용 하였는데도 scope namespace가 오염된 것입니다. 왜냐하면 같은 이름의 변수를 사용했기 때문입니다.
이렇게 새로운 block에서 변수를 쓸 때는 항상 다른 이름으로 변수를 선언해야한다는 것을 잊지 말아주세요.
코드를 작성하는 맨 아래에
whatIs
라는 함수를 만들어 놓았습니다.
이번에는 무엇을 구현하는 Assignment가 아닙니다. 위에 내용이 잘 정리 되었는지 궁금하네요!
switch
문이 있습니다. switch
문이 무엇인지 궁금한 사람은 아래에서 읽고 사용법을 익혀주세요. 👉 스위치문