표지부 해석은 패키지에서 이해한다

5953 단어 식별자
패킷을 닫고 사용할 때 자주 발생하는 오류입니다. 예를 들어 다음과 같습니다.
function foo(){
    var i;
    for(i = 0; i < 10; i++){
        setTimeout(function(){
            console.log(i);
        },1000);
    }
}

foo();    //10,10,10,10,10,10,10,10,10,10

이것은시크릿 가든 주어진 예는 setTimeout 방법에서 패키지를 만들고 외부 함수의 i 속성을 호출했습니다.set Timeout 방법을 10회 연속 호출하여 1초 후에 10개의 숫자를 연속으로 출력하였다.여기에서 setTimeout 방법을 호출하는 것은 주로 클립을 도입하는 데 쓰인다.
 
그러면 예에서 set Timeout에서 사용하는 i는 왜 순환 중의 실시간 i가 아닙니까?
여기에는 JS에서 함수가 호출될 때의 식별자 찾기 과정과 관련된다. 예에서 i는 익명 함수가 찾으려는 식별자이다.
 

우선 식별자(Identify)는 무엇입니까?

var bar = ‘Jberry’;             // 'name' is a identify

function foo(para){...}         // 'foo' is a identify
                                // 'para' are identifies                

변수의 성명 기호명'bar', 함수 성명의 함수 이름'foo', 함수의 형삼'para'3자는 표지부호이다.
 
《고성능 Javascript》라는 책에서 우리는 표지부의 검색은 로컬 환경에서 전역 환경으로의 활동 체인 (scope chain) 을 연결하는 검색 과정이라는 것을 안다.ECMAScript:
The result of evaluating an identifier is always a value of type Reference with its referenced name componentequal to the Identifier String.
따라서 필요한 식별자를 찾으면 최근 활동 대상에 대상 식별자를 이름으로 하는 인용 형식 대상을 되돌려주고 getValue (identify) 방법을 호출해서 식별자의 값을 가져옵니다.
식별자를 찾지 못하면 ReferenceError로 돌아갑니다. JS에 이 식별자 값은'undefined'입니다.
 

그러면 왜 인용된 대상이 값의 복사본이 아니라 인용된 대상을 찾았습니까?


모두가 알다시피 변수의 범위는 그 소재의 환경, 즉 역scope와 관련이 있다.
C에는 블록 레벨 영역(block-level scope, 예를 들어if,while 블록), 함수 영역(function-level scope)의 개념이 있으며, 블록 설정(block)과 정의 함수를 통해 같은 변수의 귀속을 결정할 수 있습니다.
그러나 JS에는 블록의 개념이 없고 함수역(function-levelscope)의 개념만 있으며 함수의 정의를 통해 변수의 귀속을 결정한다.JS에서 함수는 일등(first-class)인데 일반 데이터처럼 글자 그대로 만들어서 매개 변수처럼 전달하거나 다른 함수에서 값으로 되돌릴 수 있지만 C에서는 안 된다.
이 동시에 함수의 집행도 환경과 관련이 있다.
C 함수의 호출에서 호출 창고(call-stack)의 형식으로 함수의 코드를 실행합니다.함수를 실행할 때 함수의 환경과 코드 세그먼트를 창고에 눌러 넣고 창고의 환경에 따라 코드 세그먼트를 실행합니다. 함수가 실행되면 매개 변수가 창고에서 꺼집니다.이 환경은 C 함수에 필요한 매개 변수 복사본입니다.
JS의 함수 호출에서도 함수는 환경과 코드 세그먼트 두 부분으로 나뉜다.이곳의 환경은 두 부분이 있는데 일부는 함수가 생성될 때의 정적 어법 환경, 즉scopechain이다.이 환경에는 외부 환경의 표지부와 값이 저장된 일련의 변수 대상이 있다.또 일부는 함수가 실행될 때 동적으로 생성되고scopechain의 맨 앞의 활동 대상에 추가됩니다. 함수 실행 기간의 매개 변수, 내부 변수와 실시간으로 귀속된'this'도 포함됩니다.두 환경을 합치면 함수가 실행될 때의 완전한 scope chain입니다.
이를 통해 알 수 있듯이 JS의 함수는 scope chain에서 표지부를 찾는 것이고 실제로는 각 변수 대상, 활동 대상에서 찾는 과정이다.대상은 창고가 아니라 더미에 두는 것이다.따라서 C에서 호출 창고(call-stack)의 개념과 달리 여기는 호출 더미(call-heap)의 개념과 같다.매번 표지부의 검색은 무더기에서 대상을 찾는 과정이다.더미에 저장된 것은 환경을 표시하는 대상이며, 인용만 있을 뿐, 창고를 눌러서 가져오는 것이 아니다.창고를 나가는 대신 JS의 회수 메커니즘을 사용해야 합니다.
이것은 JS에서 Everything is Object의 개념을 다른 측면에서 해석한 것일 수도 있다.
 
예를 들어 1초 후에 setTimeout 방법의 익명 함수를 실행할 때 상부 foo 함수의 for 순환이 끝났고 i값은 이때 10입니다.
익명 함수는 호출할 때 i가 저장된 변수 대상을 찾습니다. 이 대상은foo 함수의 운행 환경을 나타냅니다.이 때foo 함수가 실행이 끝났기 때문에 i값은 10이 되었습니다.
따라서 i 식별자를 되돌려주는 인용 대상의 값은 10이지foo순환 i의 복사본이 아닙니다.
 
해결 방법은 간단하다. 익명 함수를 외부 함수에서 실시간으로 운행하게 하는 것이지, 외부 함수가 끝난 후에야 변수 대상에서 식별자가 필요한 것을 찾는 것이 아니다.
function foo(){
    var i;
    for(i = 0; i < 10; i++){
        setTimeout((function(e){
             return function(){
                console.log(e);
            }
        })(i),1000);
    }
}

/***********or************/
function foo(){
    var i;
    for(i = 0; i < 10; i++){
        (function(e){
            setTimeout(function(){
                console.log(e);
            },1000);
        })(i);
    }
}

foo();     //0,1,2,3,4,5,6,7,8,9

위의 분석을 보면 패키지의 정의에 따라
A closure is a pair consisting of the function code and the environment in which the function is created.
패키지는 함수체와 함수가 생성될 때의 환경으로 구성되어 있습니다.
"All functions in ECMAScript are first-class and closures"라는 말에도 이해가 되셨을 거라고 믿습니다.
수공 끝!
(C에 대한 이해가 깊지 않은데, 어떤 곳은 YY, 벽돌 두드리기를 환영합니다~)

좋은 웹페이지 즐겨찾기