2017-05-07 1 views
1

자바 스크립트는 컴파일되지 않고 실행 만합니다. 따라서 컴파일 타임 오류가 없어야하며 런타임 오류 만 있어야합니다. 그러면이 코드가 왜 작동하지 않습니까?정의되지 않은 참조로 함수 실행

function show() { console.log(x); } 
(function() { 
    var x = 42; 
    show(); 
})() 

제 질문은이 코드를 개선하는 방법이 아닙니다. 나는 그것이 나쁜 코드임을 깨닫고 그것을 수정하는 방법을 이미 알고있다 (아래 참조).

내 질문은 왜 내가 얻는거야 잡히지 않은 ReferenceError? Javascript가 런타임에 오류를 throw하는 경우에만 익명 함수 안에있는 show()을 호출 할 때 x == 42을 알고 있어야합니다.


작업 코드 :

(function() { 
    var x = 42; 
    function show() { console.log(x); } 
    show(); 
})() 

작업 코드, 최선의 선택 : JS에서

function show(y) { console.log(y); } 
(function() { 
    var x = 42; 
    show(x); 
})() 
+0

'x '는'show()'의 범위에 존재하지 않으며, 익명 함수의 범위 안에서 선언됩니다. 예, 익명 함수는 자체 범위를 갖습니다. 그리고 당신의 관련 질문 - Javascript는 인터 프리트 된 언어이고 당신은 그것을 컴파일하지 않지만 현대의 JS 엔진에서는 코드가 해석 될 때 머신 코드로 컴파일합니다. – skyline3000

답변

1

:

이 주제에 유용한 읽기는 설명 ES6 범위 지정 규칙에 있기 때문에 ES5, NOT ES6의 같다 아래는 (인한하자의 도입으로) 변경되었습니다.

자바 스크립트가 컴파일되지 않습니다. 그것은 C++/C#과 같은 다른 언어와 마찬가지로 실행을 시작하기 위해 클릭해야하는 exe/IL 코드와 같은 중간 단계가 없습니다. 컴파일 단계 후에 JS 실행이 시작됩니다.

따라서 컴파일러는 함수 선언과 변수에 대해 var declaration을 찾습니다. 따라서이 IIFE의 경우,

(function() { 
    var x = 42; 
    show(); 
})(); 

변수 선언은 하나만 있으며 변수 x는 IIFE의 범위에 등록됩니다. 이를 가변 호이 스팅이라고하며, x는 기능 수준에서 사용할 수 있습니다 (이 경우 IIFE). 이 때, 범위에 엔진 회담을 지금

(function() { 
    //registration of x in this function's scope has already happened at 
    //compile time. Notice absence of `var` 
    x = 42; 
    show(); 
})(); 

와 X의 좌변 참조 요청 : 나중에 실행시

는 인생이 개념 상처럼 보인다. x가 IIFE에 등록되었으므로 엔진이 1을 얻은 다음 42가 할당됩니다.이 부분에 대한 지금

는 :

쇼가 호출
function show() { console.log(x); } 

이 엔진은 먼저이 이름 X에 등록 된 모든 변수를 가지고 있지 않기 때문에, 글로벌 범위가 요구되고, x의 쇼 기능의 범위를 요청 (rvalue reference)는 컴파일 단계에서 전역 범위에 등록되지 않았으므로 범위에서 찾을 수 없으며 참조 오류가 발생합니다.

it should know that x == 42 at the time it calls show(), which is inside the anonymous function, correct? 

범위 지정 규칙으로 인해 외부 범위의 변수는 내부 범위에서 볼 수 있지만 그 반대는 볼 수 없습니다. x IIFE 내부는 IIFE 레벨에서 볼 수 있으며 외부 범위 외부는 볼 수 없습니다.

+0

ES6의 릴리스 이후로, 나는'let'이 함수가 아닌 블록에 범위가 있음을 알고 있지만'var'에 대해 범위 규칙이 어떻게 변경 되었습니까? 나는 'var'의 행동이 ES5에서 ES6까지 동일하다고 생각했다. – chharvey

+0

@chharvey 필자는 let 키워드를 사용하여 함수 수준 범위 지정 규칙이 더 이상 변수에 적용되지 않는다는 것을 의미했습니다 (let을 사용하여 선언 된 경우). –

+0

@chharvey 그런데 보이는 오류는 런타임 오류입니다. 코드가 실행되어 오류가 발생했습니다. –

1

변수 게양 재미입니다.

x을 클로저 (다른 함수 내에 정의 된 함수) 내부에 정의 했으므로 참조 오류가 발생했습니다. 즉, 전역 범위에서 사용할 수 없으며 show() 메서드는 존재하지 않는다는 것을 의미합니다. 처음으로 정의한 경우, 전 세계적으로는 물론 작동합니다.

즉, letconst을 사용하여 ES6 +의 스코핑이 크게 향상되었으므로 바닐라 JS를 사용하지 않는 한 훨씬 일관되고 예측 가능한 코딩 경험을 얻을 수 있습니다. How do JavaScript closures work?

1

show function은 선언되지 않은 곳에서 스코프를 가져옵니다.

관련 문제