이것은 범위 문제도 종료 문제도 아닙니다. 문제는 선언 과 표현 사이의 이해에 있습니다.
Netscape의 첫 번째 버전의 JavaScript와 Microsoft의 첫 번째 사본조차도 JavaScript 코드는 두 단계로 처리됩니다.
1 단계 : 컴파일-이 단계에서는 코드가 구문 트리 (및 엔진에 따라 바이트 코드 또는 바이너리)로 컴파일됩니다.
2 단계 : 실행-파싱 된 코드가 해석됩니다.
함수 선언 구문 은 다음과 같습니다.
function name (arguments) {code}
인수는 물론 선택 사항입니다 (코드도 선택 사항이지만 그 요점은 무엇입니까?).
그러나 JavaScript를 사용하면 표현식을 사용하여 함수를 만들 수도 있습니다 . 함수 표현식의 구문은 표현식 컨텍스트로 작성된다는 점을 제외하면 함수 선언과 유사합니다. 그리고 표현은 다음과 같습니다.
=
기호 (또는 :
객체 리터럴) 오른쪽에있는 모든 것 .
- 괄호 안의 모든 것
()
.
- 함수에 대한 매개 변수 (실제로 이미 2에서 다룹니다).
선언 과 다른 식은 컴파일 단계가 아닌 실행 단계에서 처리됩니다. 그리고이 때문에 표현의 순서가 중요합니다.
따라서 명확히하기 위해 :
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();
1 단계 : 컴파일. 컴파일러는 변수 someFunction
가 정의되어 있음을 확인하여 생성합니다. 기본적으로 생성 된 모든 변수는 undefined 값을 갖습니다. 컴파일러는 아직 값을 할당 할 수 없습니다. 값은 할당 할 값을 반환하기 위해 일부 코드를 실행하기 위해 인터프리터가 필요할 수 있기 때문입니다. 그리고이 단계에서 우리는 아직 코드를 실행하지 않습니다.
2 단계 : 실행. 인터프리터는 변수 someFunction
를 setTimeout 에 전달하려는 것을 확인합니다 . 그리고 그렇습니다. 불행히도의 현재 값 someFunction
은 정의되지 않았습니다.
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();
1 단계 : 컴파일. 컴파일러는 someFunction이라는 이름으로 함수를 선언하고 있음을 확인하고이를 생성합니다.
2 단계 : 인터프리터는 사용자 someFunction
가 setTimeout 에 전달하려는 것을 확인합니다 . 그리고 그렇습니다. 의 현재 값은 someFunction
컴파일 된 함수 선언입니다.
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();
1 단계 : 컴파일. 컴파일러는 변수를 선언 한 것을보고 someFunction
생성합니다. 이전과 마찬가지로 그 값은 정의되지 않았습니다.
2 단계 : 실행. 인터프리터는 익명 함수를 setTimeout에 전달하여 나중에 실행합니다. 이 함수에서 변수를 사용하고 있음 someFunction
을 확인하여 변수에 대한 클로저를 만듭니다. 이 시점에서의 값 someFunction
은 아직 정의되지 않았습니다. 그런 다음에 기능을 할당하는 것을 확인합니다 someFunction
. 이 시점에서의 값 someFunction
은 더 이상 정의되지 않습니다. 1/100 초 후에 setTimeout이 트리거되고 someFunction이 호출됩니다. 그 값이 더 이상 정의되지 않았기 때문에 작동합니다.
케이스 4는 실제로 케이스 3의 비트가 던져진 케이스 2의 또 다른 버전입니다.이 시점 someFunction
에서 setTimeout에 전달되어 이미 선언되어 있기 때문에 존재합니다.
추가 설명 :
setTimeout(someFunction, 10)
someFunction의 로컬 복사본과 setTimeout에 전달 된 복사본 사이에 클로저가 생성되지 않는 이유 가 궁금 할 수 있습니다 . 이에 대한 대답은 JavaScript의 함수 인수가 항상 숫자 나 문자열 인 경우 항상 값으로 전달되거나 다른 모든 항목에 대한 참조로 전달된다는 것입니다. 따라서 setTimeout은 실제로 변수 someFunction이 전달되는 것이 아니라 (이는 클로저가 생성됨을 의미 함) someFunction이 참조하는 객체 (이 경우에는 함수) 만 가져옵니다. 이것은 폐쇄를 차단하기 위해 JavaScript에서 가장 널리 사용되는 메커니즘입니다 (예 : 루프).