2013-02-23 90 views
9

我似乎無法讓我的頭繞過JavaScript變量範圍的特定情況。與我發現的其他示例和問題不同,我對嵌套函數的範圍感興趣。JavaScript本地範圍:var與此對比

我在this JSFiddle設置了一個例子。相關部分如下:

function MyObject() { 
    var self = this; 

    var a = 1; 
    this.b = 2; 

    var innerMethod = function() { 
     //1 and 2: direct reference 
     logMessage("a = " + a); // a = 1 
     //logMessage("b = " + b); // Error: b is not defined 

     //3 and 4: using this 
     logMessage("this.a = " + this.a); // this.a = undefined 
     logMessage("this.b = " + this.b); // this.b = undefined 

     //5 and 6: using self 
     logMessage("self.a = " + self.a); // self.a = undefined 
     logMessage("self.b = " + self.b); // self.b = 2 
    } 
} 

現在,據我所知,對a的引用直接起作用。 我也明白,消息3和4(this.athis.b)將失敗,因爲this引用內部函數。我也明白,第6行的作品,因爲我保存對原始對象的引用。

我不明白的是:

  • 爲什麼沒有消息1和2都工作?
  • 爲什麼消息5和6不能正常工作?
+5

發揮他們爲什麼會工作的喜愛呢?好像你正在用類似於Java或其他語言的'this'命名空間是隱含的,JS不是這種情況。 – 2013-02-23 23:28:35

+0

@FabrícioMatté我可能會無意識的這樣做(雙關語意)。我無法理解範圍是否應使變量/成員自動暴露給內部成員。它似乎並非如此,因爲它不一致。 – Alpha 2013-02-23 23:33:34

+3

@Alpha您正在比較變量('var a = 5;')與非變量但對象屬性('this.b = 10;'設置'this'引用的對象的屬性'b'到'10')。這些事情是不一樣的,因此行爲不一樣。 – Niko 2013-02-23 23:35:52

回答

4

a變量就是這個變量。它在innerMethod(它只是一個嵌套函數)範圍內是可見的,如a,它是如何聲明的(即JavaScript具有詞法範圍規則,內部函數可以看到它們在其內部定義的函數的變量)。

this與構造函數MyObject的局部範圍不一樣。

你已經看到了self是的MyObjectthis的別名,而innerMethod在自己的範圍已經覆蓋this。儘管如此,因爲this不是功能範圍的別名,所以self.athis.a都不會在這裏工作。

有關詞彙範圍的更嚴格解釋,您可以開始於維基百科:http://en.wikipedia.org/wiki/Scope_(computer_science)

您可以閱讀有關執行上下文和標識的解析規則在ECMA標準http://es5.github.com/#x10.3

+0

很好解釋。 :) – Kaeros 2013-02-23 23:33:49

+0

我更喜歡在第三段中使用['VariableEnvironment'](http://es5.github.com/#x10.3)而不是'function scope',並且聲明第一段是JS有[詞法範圍](http://stackoverflow.com/questions/1047454/what-is-lexical-scope)。但很好解釋。 – 2013-02-23 23:56:23

+0

我已經納入了一些更改,但我很猶豫是否要將VariableEnvironment交換爲函數範圍。儘管它在技術上更加正確,但我認爲函數範圍是一個更爲人熟知的來自其他語言的程序員的概念。我已將您的鏈接添加到ECMA標準。 – thebjorn 2013-02-24 11:02:46

1

這是一個範圍問題,當函數被創建時,它們會保存它們的環境(包括變量)。

因此當創建innerMethod時,它可以看到變量selfa

一個重要的概念是範圍是在聲明函數時創建的,而不是在調用函數時創建的。

在你的情況1,b沒有被聲明(這個對象是不一樣的)。

在情況5和6中,您沒有創建self.a

0

的主要原因是self不innerMethod的範圍等於thisthis是引用該函數所有者的關鍵字。對於innerMethod,它不是一個實例方法,它屬於Window。

function MyObject() { 
    var self = this; 

    var innerMethod = function() { 
     alert("inner method, self == this?: " + self == this); // false 
     alert("inner method: " + this); // [object Window] 
     alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window 
    } 

    this.outerMethod = function(){ 
     innerMethod(); 
     alert("outer method: " + this); // [object MyObject] 
     alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject 
    } 
} 

var o = new MyObject(); 
o.outerMethod(); 

您可以在here