스코프(Scope, 유효범위)는 자바스크립트를 포함한 모든 프로그래밍 언어에서, 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다.
만약 스코프가 없다면 같은 식별자 이름은 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없다.
자바스크립트에서 스코프를 구분해보면 다음과 같이 2가지로 나눌 수 있다.
전역 스코프 (Global scope)
전역 변수가 가지는 스코프
코드 어디에서든지 참조할 수 있다.
지역 스코프 (Local scope or Function-level scope)
지역 변수가 가지는 스코프
함수 코드 블록
이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.
방금 위에서 스코프
라는 단어를 참조를 위해 정한 규칙
이라고 정의했다.
블록
이라는 것은 code 에서 {..} 안을 말하며 이 바깥에 있는 변수는 참조하지 못하는 것을 말한다. 물론, 자바스크립트(ES2015 이후 문법) 에서 let 변수는 블록 레벨 스코프를 지원한다.
왜?
위에서 말했듯, 자바스크립트는 함수레벨 스코프를 따르기 때문에 함수 바깥에 선언된 var 는 전역객체의 프로퍼티이다.
블록 레벨 스코프
(main) 바깥에서 선언한 변수들이 전역 스코프를 가진다.for (var i = 0; i<10; i++) {
setTimeout(
()=>{
console.log(i)
},(i+1)*1000);
}
위의 코드를 를 보면 for 문에 선언한 var i 가 전역으로 선언이 되어있기때문에 setTimeout 1초 가 지나고 이미 10이 된 후에 console.log(i) 가 실행되기 때문에 10이 1초간격으로 열번 나온다.
그렇다면 원래 코드의 의도대로 0부터 9까지 1초 간격으로 출력되게 만드려면 어떻게 해야할까?
ES2015 문법에서는 var 를 let 으로 바꿔주어 블록 레벨 스코프로 바꾸기만 하면된다. 그러나, 이번에는 함수 레벨 스코프의 이해를 위해 바꾸지 않고 해결하는 방법을 고안해 보았다.
일단 print 라는 함수를 만들어보자.
function print (i) {
setTimeout(
()=>{
console.log(i)
},(i+1)*1000);
}
그리고 이 print 라는 함수는 for 문을 이용해서 10번 호출될 것이다.
for (var i = 0; i<10; i++) {
print (i)
}
이렇게하면 i이라는 변수가 print 함수 스코프에 참조가 제한되어서 0,1,...9 로 참조되는 것이다.
다음에는 참조에 대한 더 자세한 이야기를 다루기 위해 렉시컬 스코프를 다뤄야 겠다.