Scope는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다. 자바스크립트는 이 규칙대로 식별자를 찾는다.
변수는 전역 또는 코드 블록 (if, for, whle, try/catch 등)이나 함수 내에 선언합니다. 식별자는 자신이 어디에서 선언됐는지에 의해 자신이 유효한(다른 코드가 참조할 수 있는)범위를 갖습니다. 이 범위에 따라 코드가 참조가 가능할 수도 가능하지 않을 수도 있으며, 이와같은 규칙을 스코프라고 합니다.
만약 스코프가 없다면, 같은 식별자 이름은 모두 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없게 될 것입니다.
같은 이름의 파일을 한 곳에 둘 수 없는 것과 같습니다. 만약 디렉터리가 없다면 같은 이름의 폴더는 두개 이상 만들 수 없을 것 입니다.
🐣 쉽게 이해하기
Scope란 단어 자체를 직역하면 '범위' 라는 의미를 갖습니다. 컴퓨터 공학, javascript에서의 의미도 다르지 않습니다. 따라서 스코프는 범위를 뜻한다고 먼저 이해하고 읽는 편이 좋을 것 같습니다. 정의 자체는 "식별자 접근 규칙에 따른 유효 범위" 입니다.
javascript에서의 scope는 다음과 같이 2가지로 나눌 수 있습니다.
전역 스코프 (Global scope)
코드 어디에서든지 참조할 수 있다.
지역 스코프 (Local scope or Functoin-level scope)
함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.
모든 변수는 스코프를 가지며, 변수의 관점에서 스코프를 구분한다면 다음과 같이 2가지로 나눌 수 있습니다.
전역 변수 (Global variable)
전역에서 선언된 변수이며 어디에든 참조할 수 있다.
지역 변수 (Local variable)
지역(함수)내에서 선언된 변수이며 그 지역과 그 지역의 하부 지역에서만 참조할 수 있다.
변수 스코프 규칙
변수는 "선언 위치(전역 or 지역)"에 의해 스코프를 가지게 됩니다.
전역에 위치해 전역 스코프를 갖게된 변수는 그 어디에서도 참조가 가능합니다. 하지만, 지역에 (block or function)에 속해 지역 스코프를 갖게된 변수는 그 지역과 그 지역의 하부 지역에서만 참조할 수 있습니다.
javascript에서의 Scope는 타 언어와의 차이점이 있습니다.
예를 들어 C언어에서는 {block}level scope를 따릅니다. if문 {}안에 선언한 변수는 if문 내 {}에서만 참조가 가능합니다. 하지만 javascript는 function-level scope를 따릅니다. 참조하려는 function안에 if문이 있기만 하다면, if문 안에 선언된 변수라 할지라도 참조가 가능합니다.
단, ES6에 도입된 let 키워드를 사용하면 block-level scope를 사용할 수 있습니다
var 키워드로 선언한 전역 변수는 전역 개개체(Global Object) window의 프로퍼티 입니다.
var global = 'global';
function Fn(){
var local = 'local';
console.log(global) //'global'
console.log(local) // 'local'
}
Fn()
console.log(global) //'global'
console.log(local) // ReferenceError
위와 같이 전역에서 선언된 global은 어디에서든 참조가 가능하지만, Fn함수 안에서 선언된 local은 function-level scope를 가지므로 안에서만 참조가 되고 바깥에서는 되지 않아서 참조에러가 뜨게됩니다.
!!!화살표 함수는 block-level scope로 취급됩니다!!!
if(ture){
var x = 1;
}
console.log(x) // 1
위에 설명했든 javascript는 block-level scope가 아니라 function-level scope를 따릅니다. 따라서 function안에 선언된 변수가 아니라면 어디서든 참조가 가능합니다.
ES6부터 추가된 let키워드는 block-level scope를 갖습니다.
var x = 1;
function test() {
var x = 10;
bar();
}
function bar() { // 전역에 선언
console.log(x) // 이 곳에서 x는 상위 끝까지 올라가서 x를 찾게된다. 따라서 test()에 선언된 x에게는 아무런 영향을 받지 않는다.
}
test(); // 1
bar(); // 1
위 예제를 실행하면 1,1 이 출력되는데 그 이유는 이미 실행 단계에서 코드들의 스코프를 결정 짓기 때문입니다. javascript는 렉시컬 스코프를 따르는데, 이 경우 함수를 선언한 위치를 기준으로 스코프를 결정 짓습니다. bar는 전역에 선언되어 있기 때문에. 전역에 선언되어있는 var x = 1을 참조하게 됩니다. 즉, test에서 bar를 호출한 시점은 아무런 영향을 주지 못합니다.
스코프는 범위라고 생각하면 되고, 변수를 선언하는 위치에 따라 변수를 참조할 수 있는 범위(스코프)가 주어지며, 변수를 참조할 때에는 지역변수가 우선순위를 갖는다 예를 들어 전역 변수를 함수 내에서 재할당하고 읽어드린다면, 전역에서 선언된 값이 아니라 읽을 때 위치와 가까운 재할당한 값이 출력된다. 화살표 함수는 function이 아니라 block으로 취급되니 유의할 것! 정도로 생각을 정리했다. 호이스팅 관련 글을 적을 때 스코프에 관련된 내용을 잘 모르고 정리해서 혼잡했던 내용들이 정리됐다.