View
1.801
Download
2
Category
Preview:
DESCRIPTION
2013.04.02 스터디 팀 복습을 위한 문서.
Citation preview
JavaScript Hoisting
안 오 균
먼저,지역 변수의 유효 범위는 블럭이 아닌 함수!
function foo() { var bar = ‘bar’; console.log(bar); //--> ‘bar’ if (true) { var bar = ‘baz’; console.log(bar); //--> ‘baz’ } console.log(bar); //--> ‘baz’ }
즉시 실행 함수로 유효 범위를 제한할 수 있음.
function foo() { var bar = ‘bar’; console.log(bar); //--> ‘bar’ if (true) { (function () { var bar = ‘baz’; console.log(bar); //--> ‘baz’ }()); } console.log(bar); //--> ‘bar’ }
호이스팅(Hoisting)
변수 선언과 함수 선언은 인터프리터에 의해 함수의 맨 앞으로 끌어올려진다(옮겨진다).
* hoist = 끌어올리다
용어가 좀 헷갈릴 수 있다.
변수 선언(Variable Declaration) var foo = ‘bar’;
함수 선언(Function Declaration) function foo() {}
함수 표현식(Function Expression) var foo = function () {}; (function foo() {});
변수 선언인 경우
function foo() { console.log(bar); //--> undefined var bar = 'baz'; console.log(bar); //--> 'baz' }
아래와 동일 function foo() { var bar; // 변수 선언은 함수의 맨 앞으로 끌어올려진다.(hoisted) console.log(bar); bar = 'baz'; // 할당은 실행 시점에 수행 console.log(bar); }
for 문의 경우도 동일
function foo(arr) { for (var i = 0, len = arr.length; i < len; i++) { console.log(arr[i]); } }
아래와 동일 function foo(arr) { var i, len; for (i = 0, len = arr.length; i < len; i++) { console.log(arr[i]); } }
함수 정의인 경우
function foo() { bar(); //--> 'bar' function bar() { console.log('bar'); } }
아래와 동일 function foo() { function bar() { console.log('bar'); } bar(); }
함수 표현식인 경우 (변수 선언과 동일)
function foo() { bar(); //--> ReferenceError var bar = function () {}; bar(); // 호출되지 않음 }
아래와 동일 function foo() { var bar; bar(); bar = function () {}; bar(); }
변수 선언은 호이스팅으로 맨 앞으로,변수 할당은 실행시점에 수행됨.
호이스팅으로 헷갈릴 수 있으니,함수의 맨 앞 부분에 한 개의 var만 쓸 것을 권장.
function foo() { var a = 1, b = 2, c = 3; }
그치만, 눈을 크게 떠야할 때가 있음.
function foo() { var a = 1, b = 3, c = 4; d = 2; }
오류 없이 실행되며, 변수 d는 전역으로 선언됨.린트 툴을 사용할 것을 권장.
디버깅이 어려운 경우도 있음.
function foo() { var a = 1, b = getComplexValue(a), // 브레이크 포인트를 잡기 어려움 c = b + 3; }
상황에 따라 var로 나누는 것도 나쁘지 않은 선택.
function foo() { var a = 1; var b = getComplexValue(a); var c = b + 3; }
또한, 분기문 내에 함수 정의를 넣지 말 것.
function foo(condition) { if (condition) { function bar() { console.log('first bar'); } } else { function bar() { console.log('second bar'); } } bar(); } foo(true); //--> 'second bar' foo(false); //--> 'second bar'
함수 정의 호이스팅에 따라 아래와 같기 때문.
function foo(condition) { function bar() { console.log('first bar'); } function bar() { console.log('second bar'); } if (condition) { } else { } bar(); }
* ES5 strict 모드에서는 SyntaxError 발생
상황에 따라 동적으로 할당하고 싶다면. function foo(condition) { var bar; if (condition) { bar = function () { console.log('first bar'); }; } else { bar = function () { console.log('second bar'); }; } bar(); } foo(true); //--> 'first bar' foo(false); //--> 'second bar'
개인적으로는, var는 맨 위에,함수는 읽어내려가기 편하게 작성하는 것을 선호함.
function foo() { var a, b, c;
doAll();
function doAll() { doA(); doB(); } function doA() {} function doB() {} }
하지만 리턴문 뒤의 함수 정의는,문맥 상 그다지 좋은 것 같지 않음.
function foo() { return bar();
function bar() { return ‘baz’; } }
* 함수 정의 호이스팅으로 문제 없이 실행됨.
끝.
부록. 좀 더 자세히 알아보면.
function test(a, b) { console.log(a, b, c, d); var c = 10; function d() {} } test(10);
위와 같은 함수가 전역 범위에서 실행될 때.
다음과 같은 식으로 실행됨.
1. foo()가 호출되면,2. foo()의 실행 컨텍스트가 생성되고,3. 실행 컨텍스트는 함수를 실행하기 전 활성화 객체를 생성한다.4. 활성화 객체에는 파라미터 정보, 변수 선언, 함수 정의가 포함된다.5. 함수가 실행되고 변수를 만났을 때엔, 유효범위 체인에 따라 활성화 객체에서 먼저 찾고, 상위 탐색을 진행한다.
이 때, 활성화 객체에는 다음 값들이 할당된다.
- 파라미터로 전달된 값 파라미터의 이름과 값을 할당 없는 경우 undefined로 할당
- 모든 함수 선언 함수의 이름과 정의를 할당 이미 정의되어 있는 경우 덮어씀
- 모든 변수 선언 변수의 이름과 undefined를 할당 이미 정의되어 있는 경우 할당하지 않음
즉, 아래 코드가 실행되기 전, function test(a, b) { console.log(a, b, c, d); var c = 10; function d() {} } test(10);
활성화 객체(Activation Object)는 다음과 같이 생성된다. AO = { a: 10, b: undefined, c: undefined, d: <reference to function ‘d’> };
실행 시점에서 변수를 만났을 때엔,활성화 객체의 값을 찾거나 설정한다.
function test(a, b) { console.log(a, b, c, d); // 각각 AO[‘a’], AO[‘b’], AO[‘c’], AO[‘d’]의 값 // 10, undefined, undefined, function var c = 10; // AO[‘c’] = 10; 과 동일하다. function d() {} } test(10);
함수 표현식은 활성화 객체에 할당되지 않는다.
function test() { var foo = function bar() {}; // foo는 AO에 존재하지만, bar는 존재하지 않는다. // bar의 접근을 시도하면 ReferenceError가 발생한다. (function baz() {}); // 마찬가지로 baz도 AO에 할당되지 않는다. }
호이스팅은 활성화 객체의 할당 방식에 따른 현상.
function foo() { console.log(bar); //--> function ‘bar’ // AO[‘bar’] = <reference to function ‘bar’> var bar = 10; function bar() {}; var bar = 20; }
정말 끝.
Recommended