식별자가 유효한 범위. (식별자를 검색할 때 사용하는 규칙)
모든 식별자(변수명, 함수명, 클래스명)는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정된다.
스코프를 통해 식별자 이름의 충돌을 방지할 수 있다. 스코프 내에서 식별자는 유일해야 하지만, 다른 스코프에는 같은 이름의 식별자를 사용할 수 있다. (=namespace)
function add(x, y) {
// 매개변수 x, y는 함수 몸체 내에서만 참조 가능 = 매개변수의 스코프는 함수 몸체 내부
console.log(x, y); // 2, 3
return x + y;
}
add(2, 3);
console.log(x, y); // Reference Error: x is not defined
var x = 'global'; // 바깥 영역에 선언된 x 변수는 어디서든 참조 가능
function foo() {
var x = 'local'; // 지역 변수 (바깥의 변수와 별개의 변수)
console.log(x); // local
}
foo();
console.log(x); // global
function foo() {
var x = 1;
var x = 2; // var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언 허용
console.log(x); // 2
}
foo();
function bar() {
let x = 1;
let x = 2; // let, const로 선언된 변수는 같은 스코프 내에서 중복 선언 허용x
// SyntaxError: Identifier 'x' has already been declared
}
bar();
코드의 가장 바깥 영역. 전역에 변수를 선언하면 전역 스코프를 갖는 전역 변수가 되며, 전역 변수는 어디서든지 참조할 수 있다.
함수 몸체 내부. 지역에 변수를 선언하면 지역 스코프를 갖는 지역 변수가 된다. 자신이 선언된 지역과 하위 지역(중첩 함수)에서만 참조할 수 있다.
// 전역 스코프
var x = 'global x';
function outer() { // 지역 스코프
var y = 'outer local y'; // 자신의 지역 스코프와 하위 지역 스코프에서 유효
console.log(x); // global x
console.log(y); // outer local y
function inner() { // 지역 스코프
var x = 'inner local x';
console.log(x); // inner local x
console.log(y); // outer local y
}
inner();
}
outer();
console.log(x); // global x
console.log(y); // Reference Error: z is not defined
스코프가 함수의 중첩에 의해 계층적 구조를 갖는 것.
외부 함수의 지역 스코프를 중첩 함수의 상위 스코프라고 한다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며, 선언된 변수를 검색한다.
코드 블록이 아닌, 함수에 의해서만 지역 스코프가 생성된다는 의미.
var x = 1;
if (true) {
// var 변수는 함수의 코드 블록만을 지역 스코프로 인정하므로, x는 전역 변수.
// 의도치 않게 변수 값이 변경되는 부작용을 발생시킴.
var x = 10;
}
console.log(x); // 10
// let/const를 사용해서 변수를 선언하면 블록 레벨 스코프를 지원.
함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정하는 것.
=> 자바스크립트를 비롯한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따른다.
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
// bar는 전역에서 생성된 함수이므로 상위 스코프인 전역의 x값을 기억
foo(); // 1
bar(); // 1