Scope
스코프는 자바스크립트를 포하함 모든 프로그래밍 언어의 기본적인 개념입니다.
스코프란 참조 대사 식별자를 찾아내기 위한 규칙입니다. 자바스크립트는 이 규칙대로 식별자를 찾습니다.
프로그래밍은 변수를 선언하고 값을 할당하며 변수를 참조하는 기본적인 기능을 제공하며 이것으로 프로그램의 상태를 관리할 수 있습니다. 변수는 전역 또는 코드블록이나 함수 내에 선언하며 코드 블록이나 함수는 중첩될 수 있습니다. 식별자는 자신이 어디에서 선언됐는지에 의해 자신이 유요한 범위를 갖습니다.
만약 스코프가 없다면 어떻게 될까요? 스코프가 없다면 같은 식별자 이름은 충돌을 일으키므로 전체에서 하나밖에 사용할 수 없습니다.
스코프의 구분
자바스크립트에서 스코프를 구분하면 2가지로 나눌 수 있습니다.
- 전역 스코프 (Global scope) : 코드 어디서든지 참조 가능
- 지역 스코프(Local scope or Function-level scope) : 함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조 가능
모든 변수는 스코프를 갖는데 변수 관점에서 구분하면 스코프와 유사하게 2가지로 나눌 수 있습니다.
- 전역 변수(Global variable) : 전역에서 선언된 변수이며, 어디에든 참조 가능
- 지역 변수(Local variable) : 지역(함수)내에서 선언된 변수이며 그 지역과 그 지역의 하부 지역에서만 참조 가능
자바스크립트 스코프의 특징
자바스크립트의 스코프는 타 언어와는 다른 특징을 가지고 있습니다.
대부분의 c-family 언어는 블록 레벨 스코프를 따릅니다. 블록 레벨 스코프란 코드블록({...})내에서 유요한 스코프를 의미합니다.
int main(void) {
// block-level scope
if (1) {
int x = 5;
printf("x = %d\n", x);
}
printf("x = %d\n", x); // use of undeclared identifier 'x'
return 0;
}
위의 코드를 보면 if문 내에서 선언한 x는 if문 코드 블록 내에서만 유효합니다.
하지만 자바스크립트는 함수 레벨 스코프를 따릅니다. 함수 레벨 스코프란 함수 코드 블록 내에서 선언된 변수는 함수 코드 블록 내에서만 유효하고 함수 외부에서는 유효하지 않다는 것입니다.
단, ECMAScript 6에서 도입된 let keyword를 사용하면 블록 레벨 스코프를 사용할 수 있습니다..
var x = 0;
{
var x = 1;
console.log(x); // 1
}
console.log(x); // 1
let y = 0;
{
let y = 1;
console.log(y); // 1
}
console.log(y); // 0
전역 스코프
전역에 변수를 서언하면 이 변수는 어디서든지 참조할 수 있습니다. var 키워드로 서언한 전역 변수는 전역 객체 window의 프로퍼티입니다.
var global = 'global';
function foo() {
var local = 'local';
console.log(global);
console.log(local);
}
foo();
console.log(global);
console.log(local); // Uncaught ReferenceError: local is not defined
비 블록 레벨 스코프
if (true) {
var x = 5;
}
console.log(x);
변수 x는 코드 블록 내에서 서언되었지만 자바스크립트는 함수 레벨 스코프를 따르기 때문에 코드블록 내에서 선언되었다 할지라도 함수 밖에서 선언되었으면 전역 스코프를 갖게됩니다.
함수 레벨 스코프
var x = 'global';
function foo() {
var x = 'local';
console.log(x);
}
foo(); // local
console.log(x); // global
전역변수 x와 지역변수 x가 중복 선언되었습니다. 함수 내에서는 전역과 지역 모두 참조 가능하나 변수명이 중복된 경우, 지역변수를 우선하여 참조합니다.
var x = 'global';
function foo() {
var x = 'local';
console.log(x);
function bar() { // 내부함수
console.log(x); // local
}
bar();
}
foo();
console.log(x); // global
내부함수는 자신을 포함하고 있는 외부함수의 변수에 접근할 수 있습니다.
함수 bar에서 참조하는 변수 x는 함수 foo에서 선언한 지역변수입니다. 이는 실행 컨텍스트의 스코프 체인에 의해 참조 순위에서 전역변수 x가 뒤로 밀렸기 때문입니다.
var x = 10;
function foo() {
x = 100;
console.log(x);
}
foo();
console.log(x); // 100
함수 영역에서 전역변수를 참조할 수 있으므로 전역변수의 값도 변경할수 있습니다.
렉시컬 스코프
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
위 예제의 실행 결과는 함수 bar의 상위 스코프가 무엇인지에 따라 결정됩니다. 두가지 패턴을 예측할 수 있는데 첫번째는 함수를 어디서 호출하였는지에 따라 상위 스코프를 결정하는 것이고 두번째는 함수를 어디서 선언하였는지에 따라 상위 스코프를 결정하는 것입니다. 첫번째 방식으로 함수의 상위 스코프를 결정한다면 함수 bar의 상위스코프는 함수 foo와 전역일 것이고, 두번째 방식으로 함수의 스코프를 결정한다면 함수 bar의 스코프는 전역일 것입니다.
프로그래밍 언어는 이 두가지 방식 중 하나의 방식으로 함수의 상위 스코프를 결정합니다. 첫번째 방식을 동적 스코프라 하고, 두번째 방식을 렉시컬 스코프 또는 정적 스코프라 합니다. 자바스크립트를 비롯한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따릅니다.
암묵적 전역
var x = 10; // 전역 변수
function foo () {
// 선언하지 않은 식별자
y = 20;
console.log(x + y);
}
foo(); // 30
foo 함수가 호출되면 자바스크립트 엔진은 변수 y에 값을 할당하기 위해 먼저 스코프 체인을 통해 선언된 변수인지 확인한다. 이때 foo 함수의 스코프와 전역 스코프 어디에서도 변수 y의 선언을 찾을 수 없으므로 참조 에러가 발생해야 하지만 자바스크립트 엔진은 y = 20
을 window.y = 20
으로 해석하여 프로퍼티를 동적 생성한다. 결국 y는 전역 객체의 프로퍼티가 되어 마치 전역 변수처럼 동작한다. 이러한 현상을 암묵적 전역(implicit global)이라 한다.
하지만 y는 변수 선언없이 단지 전역 객체의 프로퍼티로 추가되었을 뿐이다. 따라서 y는 변수가 아니다. 따라서 변수가 아닌 y는 변수 호이스팅이 발생하지 않는다.
최소한의 전역변수 사용
전역벼수 사용을 최소화하는 방법 중 하나는 애플리케이션에서 전역변수 사용을 위해 다음과 같이 전역변수 객체 하나를 만들어 사용하는 것입니다.(더글라스 크락포트의 제안)
var MYAPP = {};
MYAPP.student = {
name: 'Lee',
gender: 'male'
};
console.log(MYAPP.student.name);
'프론트엔드 스터디 > Javascript' 카테고리의 다른 글
클로저(closure)란??? (0) | 2021.07.13 |
---|---|
자바스크립트 실행 컨텍스트 (0) | 2021.07.12 |
Prototype이란? (0) | 2021.07.12 |
자바스크립트에서 함수란? (0) | 2021.07.09 |
strict mode(엄격모드)란? (0) | 2021.07.09 |