2012-07-09 5 views
2

자바 스크립트 코드의 스 니펫이 있습니다.이 코드는 ""의 JavaScript 닌자의 비밀 "(John Resig 책)에 있습니다. 변수의 동작을 이해하는 데 문제가 있습니다.변수 범위 설명

(function() { 
    var results; 
    this.assert = function assert() { 
     var li = document.createElement("li"); 
     results.appendChild(li); 
     return li; 
    }; 
    this.test = function test(name, fn) { 
     results = document.getElementById("results"); 
     results = assert().appendChild(document.createElement("ul")); 
     fn(); 
    }; 
})(); 
window.onload = function() { 
    test("A test.", function() { 
     assert(); 
     assert(); 
    }); 
}; 

내 문제가 결과 변수 : 다음 (일본어 하나에 대해 간략화) 코드이다. "test"함수를 입력하면 결과 변수의 값은 "ul # results"이되고 appendChild 함수의 결과로 "ul" 값이됩니다. 그러나 "fn()" 함수를 입력하면 "results"값은 여전히 ​​"ul # results"입니다. 왜? 나는이 변수의 범위를 이해하기가 어렵다.

누군가이 주제를 이해하도록 도와 줄 수 있습니까?

대단히 감사합니다.

답변

2

변수는 익명 함수의 범위에서 만들어집니다. asserttest은 모두 과 동일한results에 액세스합니다.

+0

네,하지만 왜 fn() 함수를 입력 할 때 결과 변수의 값이 다른가요? – user1512966

+0

그 시점에서 왜 다른 가치가 있다고 생각합니까? – ThiefMaster

+0

! 나는 그 문제를 발견했다. 문제는 fn() 함수에서 변수 결과가 표시되지 않는다는 것입니다. 그것은 "테스트"와 "assert"기능에서만 볼 수 있지만 HTML에서 "결과"를 "id"로 가지는 ul 요소가 있고 방화 광구에서 결과를 가리키면이 "id"값을 봅니다 마우스로 변수. – user1512966

0

이것은 무엇보다 혼란 스럽지만 기본적으로 코드는 DOM의 요소에 자식 요소를 재귀 적으로 추가합니다. 이는 클로저에 변수 "결과"가 정의되어 있기 때문에 가능합니다. 그 변수는 그 범위 내에서 살아 있습니다.

여기에 자바 스크립트의 변수 범위를 설명하는 몇 가지 테스트를 보여주는 기사가 있습니다. 여기에있는 것처럼 폐쇄에 대해 이야기하지 않는다는 점을 명심하십시오. 그러나 당신이 달려들 다른 것들을 설명하는 데 도움이 될 수 있습니다.

http://www.computerhowtoguy.com/an-introduction-to-javascript-variable-scope/

이 처리는 단계적으로 설명한다 다음 창로드 함수

  1. 코드는 "윈도우"레벨 범위를 가질 것이다. "this"를 출력한다면 "window" 객체를 얻을 수 있습니다.
  2. onload 함수는 "test"를 호출합니다. "test"( this.test 또는 window.test라고 쓰여 있음)가 닫힙니다. 이유는 그것이 인데,이 줄 때문에 클로저의 "test"함수는 다음과 같습니다. this.test = ... 클로저가 창 수준에서 실행되었으므로 "this"는 "window"개체를 참조합니다.
  3. "test"함수 호출에서 "this"는 "window"객체를 참조합니다. 위의 assert 함수는 this.assert = ... (window.assert)로 정의되었으므로 창 객체 수준에 있습니다. == window.assert를 선언했다면, 둘 다 같은 (함수) 객체에 대한 두 개의 이름이기 때문에 "true"가됩니다.
  4. 이 줄은 다음과 같이 실행됩니다. assert(). appendChild (document.createElement ("ul")) assert 함수는 그 뒤에 오는 항목보다 먼저 실행됩니다. 그럼 어설 션 코드로 들어가 ...
  5. "this"는 여전히 "창"개체입니다.로컬 변수 "li" 이 작성되어 문서 요소에 아직 첨부되지 않은 새 DOM 요소를 참조합니다 ( ). 그런 다음이 새로운 li 요소를 에 "결과"DOM 요소에 추가합니다. 이제 DOM 개체의 일부입니다. li 요소에 대한 자바 스크립트 참조가 반환됩니다.
  6. 이제 assert(). appendChild (document.createElement ("ul")) appendChild 함수가 호출되어 새로 작성된 'li'요소 에 'ul'요소를 추가합니다. 다음으로, 우리의 javascript "results"객체는 다시 한번 새로 할당 된 입니다. 이번에 새로 생성 된 ul 요소입니다. 마지막으로, 'fn'(우리의 익명 함수가 돌아왔다)이 호출됩니다.
  7. "fn"... "this"는 여전히 윈도우를 참조합니다. assert가 호출되면, 여전히 assert가 window.assert 함수에 대한 참조가됩니다. 새로운 li 요소가 생성되어 "results"변수에 추가됩니다. Rememeber, "결과"가 할당 된 마지막 항목은 ul 요소 였으므로 여기에 새로운 li을 추가합니다.

DOM 구조 것 같은이 시점 모습 뭔가 :

<div id="results"> 
    <li> 
     <ul> 
      <li></li> 
     </ul> 
    </li> 
</div> 

그래서 코드가 물건의 같은 종류로 이동합니다 ...이 코드가 개정

, 지금 의견이 있습니다 :

// the following is a closure. a sort of isolated container with its own scope. 
(function() { 
    // results is not globally scoped, only scoped at the closure level, 
    // since its defined with "var". 
    var results; 

    // "this" is the calling object. (ie: window object) 
    this.assert = function assert() { 

     // since "var" is used "li" is part of this function. 
     var li = document.createElement("li"); 

     // results (at the closure level) appends a child at this function's level. 
     results.appendChild(li); 

     // return a javascript reference to the new DOM element. 
     return li; 
    }; 

    // again "this" is the calling object. when called in onload below, "this" is the window object. 
    this.test = function test(name, fn) { 

     // results refers to the closure level results variable, since var is ommitted. 
     // this is a reference to an element in the DOM. 
     results = document.getElementById("results"); 

     // changing the variable now. the DOM object "results" is NOT altered by this assignment, since 
     // javascript is separate from the DOM. 
     // NOTE: the assert function was previously assigned to the window object previously. so stuff in that 
     // function will be window scoped. 
     results = assert().appendChild(document.createElement("ul")); 

     // call fn 
     fn(); 
    }; 
})(); 

window.onload = function() { 

    // at this point, "this" is the "window" object. 
    // "test" is part of the closure above. in the closure the test function is assigned 
    // to "this". since we are calling the function here, "this" will be the window object in the 
    // closure for this call. 
    test("A test.", 
     // an anonymous function. this is really just an object passed into the "test" function 
     function() { 
      assert(); 
      assert(); 
     } 
    ); 
};