2014-10-18 107 views
0
Name = 'window data'; 
document.Name = 'current document data'; 

(function(window, document) { 
    var Name = 'local data'; 

    var myObj = { 
     Name: 'object data', 
     f: function() { 
      alert(this.Name); 
     } 
    }; 

    myObj.newFun = function() { 
     alert("Local scope " + Name + "\nObject Scope : " + this.Name); 
    } 

    function testFun() { 
     alert("Window Scope : " + window.Name + 
      "\nLocal Scope : " + Name + 
      "\nObject Scope : " + this.Name + 
      "\nCurrent document Scope : " + document.Name 
     ); 
    } 

    myObj.newFun(); 
    //testFun(); // Promts see "Object Scope : window data", but suppose to be "Object Scope : local data" 
    // did not found the answer 
    testFun.call(myObj); 
    testFun.bind({ 
     Name: "name injected" 
    })(); 

})(window, document); 

我試圖在自執行匿名塊內調用testFun()時發現了一個奇怪的行爲。我在代碼旁邊添加了一條評論,說明實際發生的事情和我的預期。Javascript strage scope behavior

任何人都可以解釋爲什麼會發生這種情況嗎?

回答

0

testFun上下文是window,這樣的行爲是完全正常的(調用testFun()將在window上下文中運行的話)。下面的行,testFun.call(myObj)將導致所需的行爲(call使用第一個參數作爲上下文或this調用函數)。

請記住,你在自執行匿名塊(或立即函數)的閉包,這是不一樣的上下文。任何不作爲方法綁定到對象的函數的上下文始終是window,無論它是否關閉。但是,它是關閉的,無論函數是在哪裏聲明的,所以如果你要在最後一個函數返回函數並將其分配給外部變量,alert(Name)將顯示local data而不是window data,因爲testFun是在關閉中聲明的Name等於local data

爲了進一步澄清:

// global closure scope, context (this) is window 
Name = 'window data'; 
document.Name = 'current document data'; 

var testFun = (function(window, document) { 
    // immediate closure scope, context is still window 
    var Name = 'local data'; 

    var myObj = { 
     Name: 'object data', 
     f: function() { 
      // myObj.f closure scope. immediate closure scope is available and superseeds global closure scope. context is myObj 
      alert(this.Name); // 'object data' 
     } 
    }; 

    myObj.newFun = function() { 
     // newFun closure scope. immediate scope available and superseeds global scope. context is myObj 
     alert("Local scope " + Name + "\nObject Scope : " + this.Name); // outputs 'local data' (from immediate closure scope) and 'object data' (from myObj.Name) 
    } 

    function testFun() { 
     // testFun closure scope. immediate scope available and superseeds global scope. context is window 
     alert("Window Scope : " + window.Name + // 'window data' 
      "\nLocal Scope : " + Name + // 'local data (from immediate scope) 
      "\nObject Scope : " + this.Name + // 'window data' (remember this === window) 
      "\nCurrent document Scope : " + document.Name // 'current document data' 
     ); 
    } 

    myObj.newFun(); 
    //testFun(); // Promts see "Object Scope : window data", but suppose to be "Object Scope : local data" 
    // did not found the answer 
    testFun.call(myObj); // context for testFun is changed to myObj **for this call only**, this.Name === 'object data' 
    testFun.bind({ 
     Name: "name injected" 
    })(); // context is the newly created object **for this call only**, this.Name === 'name injected' 

return testFun; 
})(window, document); 

testFun(); // will output same as if called from within immediate function, because immediate scope survives immediate function's execution and is available to testFun (and superseeds global scope) 

alert(Name); // 'window data' (global scope is still valid and is available to all statements declared outside immediate scope) 
+0

我想我明白了一下閱讀您的評論之後。自執行匿名塊的執行上下文是「窗口」。由於testFun()沒有在任何對象下定義,testFun()的執行上下文也是「窗口」。只要我在做testFun.call(myObj),它的執行上下文就是「myObj」。我對嗎? – 2014-10-18 18:03:46

+1

是的,就是這樣:) – 2014-10-18 18:36:59

+0

非常感謝你:) – 2014-10-18 19:30:27