Javascript Scope Chain

JavaScript 스코프(Scope)란?

Scope는 영역 범위라는 뜻으로 자바스크립트의 영역 범위는 어느 범위까지 참조하는지 즉, 변수와 매개변수(parameter)의 접근성과 생존기간을 뜻하며 유효범위는 크게 두 가지로 나뉘게 되는데 아래 스코프 체인에서 설명하는 활성화객체(Active Object)와 전역객체(Global Object) 이다.
참고로 ES5까지는 함수 단위의 스코프를 가진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 전역 유효범위 스코프 (Global Scope)
var a = 1;
var b = 2;

if (a < b) {
var i = 3;
} else {
var i = 4;
}

var c = function() { // 함수 단위의 스코프가 시작
var a = 5;
var d = 6;

console.log(a); // 5, 현재 지역 유효범위 스코프(Local Scope)에 a 변수가 있기 때문에 현재 지역범위 스코프에 있는 a 변수 값을 출력
};

console.log(i); // 3, 함수 단위의 스코프이기 때문에 같은 전역 유효범위 스코프 공간에 있다고 간주해서 변수를 공유하기 때문에 사용 가능
c();
console.log(d); // Uncaught ReferenceError: d is not defined, 함수 단위의 스코프이기 때문에 함수에서 쓰인 변수는 함수에서만 사용 가능

가존 프로그래밍 언어들은 블록 단위의 스코프라고 해서 if, for 문등 별도의 스코프를 가졌던거에 비해 위에 코드처럼 자바스크립트에서는 함수 단위 스코프 개념이기 때문에 전역 유효범위 스코프로 인식한다.

자바스크립트 스코프 체인

자바스크립트 성능을 다루는 부분에 항상 나오는 부분이 이 스코프 체인(Scope Chain) 이다.
런타임 환경에서 가장 많이 발생되 브라우저의 작업 가운데 자바스크립트의 실행 성능을 저해하는 요인이 변수 객체 함수 등의 메모리상의 위치를 탐색하는 일이다.

스코프 체인

자바스크립트의 함수를 실행하면서 어떤 속성(변수 객체 등)에 접근해야 할 때 해당 속성을 효율적으로 탐색하도록 속성을 일정한 객체 단위로 분류하고 각 객체에 접근하기 위한 객체의 참조를 특정한 공간에 저장하게 되는데 이 공간이 바로 스코프 체인이다.
스코프 체인의 구송요소에는 활성화객체(Active Object)와 전역객체(Global Object)가 있다.

활성화 객체 전역 객체
함수내부에서만 접근 가능한 지역변수나 this, aguments 객체 등의 속성 함수 외부에서도 접근 할 수 있는 window, document, 전역함수 전역변수등의 속성

실행 문맥(Execution Context)은 함수가 동작하는 환경을 나타내며, 브라우저 내부에서 사용되는 객체이다 샐행 문맥은 함수가 실행될 때 새로 생성되고 함수가 종료될 때 소멸되며 함수의 스코프 체인에 대한 참조를 가지고 있게 된다. 함수는 어떤 속성에 접근해야 할 때 실행 문맥을 통해 스코프 체인에 접근한다.
실행 문맥은 자신과 연관된 함수의 스코프 체인을 참조하고 있으며, 함수에서 접근해야할 어떤 속성의 탐색경로는 ‘실행 문맥 > 스코프 체인 > 활성화 객체 > 스코프 체인 > 전역 객체’ 와 같이 구성된다.

지역 변수를 활용한 스코프 체인 색 성능 개선

속성의 탐색 경로를 어떻게 줄여야 자바스크립트가 좋은 성능을 낼 수 있는지 알아보겠.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 함수 내에서 전역 스코프 변수에 직접 접근하는 예제
window.htmlstring = [];

function makeList() {
htmlstring.push('<ul>');

for (var i = 0, len = 100; i < len; i++) {
htmlstring.push('<li>value:' + i + '</li>');
}

htmlstring.push('</ul>');
}

makeList();

makeList() 함수가 실행되면 함수 내부에서 htmlstring, i 속성에 접근하기 위해 스코프 체인을 탐색한다. i 변수는 실행 중인 함수의 지역변수이므로 처음 탐색하는 활성화 객체에서 찾을 수 있다.
그러나 htmlstring 객체는 활성화 객체에 먼저 접근해서 탐색하지만 찾지 못하고 다시 전역 객체를 탐색해서 찾아야 한다.

다음과 같이 코드를 스코프 체인을 고려해서 리팩토링하면 성능을 향상 시킬 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 함수 지역변수로 참조해 전역 스코프 변수에 접근하는 예제
window.htmlstring = [];

function makeList() {
var htmlstr = htmlstring;

htmlstring.push('<ul>');

for (var i = 0, len = 100; i < len; i++) {
htmlstring.push('<li>value:' + i + '</li>');
}

htmlstring.push('</ul>');
}

makeList();

수정한 코드에서 추가한 var htmlstr = htmlstring; 부분이 성능 개선의 핵심이다. 전역 객체에 존재하는 htmlstring 속성을 makeList() 함수의 자역변수에 저장해서 활성화 객체에서 바로 찾을수 있게 한 것이다.
물론 var htmlstr = htmlstring; 구문을 실행하는 동안 htmlstring 속성에 접근해야 하므로 최초 한 번은 활성화 객체와 전역 객체를 모두 탐색해야 하지만 그 이후에는 활성화 객체에 저장된 htmlstr 속성으로 전역변수인 htmlstring 객체에 접근할 수 있으니 활성화 객체를 거쳐 전역 객체까지 탐색할 필요가 없어진다.

코드 최적화 리팩토링 이전 코드에서는 htmlstring 객체를 찾으려면 ‘실행 문맥 > 스코프 체인 > 활성화 객체 > 스코프 체인 > 전역 객체’와 같이 동일한 탐색경로를 7번을 거치게 된다.
하지만 리팩토링 한 코드에서는 var htmlstr = htmlstring; 구문을 실행할 경우 최초 한 번만 ‘실행 문맥 > 스코프 체인 > 활성화 객체 > 스코프 체인 > 전역 객체’와 같은 속성 탐색 경로를 거친다.
그 이후 window 객체의 htmlstring 속성에 접근해야 하는 것은 지역변수 htmlstr 속성에 접근하는 것으로 대체되어 ‘실행 문맥 > 스코프 체인 > 활성화 객체’와 같이 단축된 탐색 경로를 거치므로 실행 속도가 더 빠르게 향상 된다.

참조

공유하기