2013-12-16 87 views
0

我做了一個JavaScript的實驗在瀏覽器的控制檯 -做了一些JavaScript實驗,需要你的幫助,瞭解意外結果

首先,我創建了一個新對象foo如下

var foo = { 
    bar: function() { return this.baz; }, 
    baz: 1 
    }; 

現在,當我運行下面的代碼又在控制檯返回"number"

(function(){ 
    return typeof foo.bar(); 
    })(); 

但是當我運行下面的匿名函數返回"undefined"

(function(){ 
    return typeof arguments[0](); 
    })(foo.bar); 

至於我在上面的函數返回foo.bar(也被下面的例子證明)知道arguments[0]那麼爲什麼上面的代碼返回"undefined"代替"number"


當我運行

 (function(){ 
     return arguments[0]; 
     })(foo.bar); 

回報function() { return this.baz; }


而且

(function(){ 
    return typeof arguments[0]; 
    })(foo.bar()); 

返回"number"那麼爲什麼不

(function(){ 
    return typeof arguments[0](); 
    })(foo.bar); 

返回相同嗎? JavaScript中是否有任何基本法律在這裏工作?

+0

在第二個測試中,您將foo.bar作爲參數傳遞,但foo.bar不是屬性,而是一個函數。你可以嘗試傳遞foo.bar()作爲參數並檢查結果。 – ReX357

回答

1

讓我簡化問題...

var foo = { 
    bar: function() { return this.baz; }, 
    baz: 1 
}; 


var ref = foo.bar; 

console.log(typeof ref()); // undefined 
console.log(typeof foo.bar()); // number 

這是因爲「這個」函數對象「酒吧」裏並不總是指「富」 。它改變你如何稱呼它。如果你從一個不是foo的對象調用它,它會顯示未定義的。請注意,ref不是foo而是foo.bar。

現在,如果你改變富在這兩種情況下,它會給 '號' ......輸出

var foo = { 
    bar: function() { return foo.baz; }, 
    baz: 1 
}; 

注意

console.log(ref === foo.bar); // true 

但FOO。bar()不等於ref()(在第一種情況下),因爲當你調用foo.bar()時,JavaScript引擎將foo作爲'this'傳遞,但是當你調用最初是window.ref()的ref()時,它在非瀏覽器環境下傳遞窗口對象(或其他全局對象)爲'this'

2

this取決於如何調用函數。使用點符號時,JavaScript將this的上下文設置爲接收者。在你的情況下,沒有接收器,但是對函數的引用,所以你失去了上下文。你必須明確地傳遞:

arguments[0].call(foo); 

arguments[0]是相同的功能對象foo.barthis值是動態的。在foo.bar(),this被賦值爲foo,因爲您使用了foo.(點符號)。但在arguments[0]()沒有點(沒有接收器),所以this是默認值,或window

這是相同的功能,但不同的調用。

+0

我認爲'arguments [0]'與'foo.bar'相同。 'foo.bar()'在這裏正確地工作(第二個測試)和'arguments [0]()'不是,爲什麼? – rkb

+0

它是相同的函數對象,但'this'是動態的。在'foo.bar'中''this'因爲使用'foo.'(點符號)而被賦值爲'foo'。但在'arguments [0]()'中沒有點(沒有接收器),所以'this'是默認值,或者'window'。 – elclanrs

+0

請您解釋一下JavaScript解釋器的工作原理。就像它首先用'foo.bar'替換'arguments [0]',然後'arguments [0]()'和'foo.bar()'一樣,然後嘗試運行'foo.bar()'。這個過程與第二次測試有何不同。 'arguments [0]'的作用是不同的? – rkb

1

詳細闡述elclanrs的答案。

foo.bar是一種方法;如何做某事的指示。在面向對象的編程語言中,唯一可以使用該指令的對象是foo或與foo有關的對象;但在JavaScript中,任何人都可以嘗試運行它,如果代碼要求他們。

在你的第二個匿名函數中,你得到一個方法來運行,運行它,並返回結果的類型。但是,這不是運行此功能的foo;它是匿名的,因此window是運行它的對象。 window運行foo,它試圖返回this.baz;然而,window沒有baz,所以這就是爲什麼你得到未定義。

爲了進一步測試它,嘗試設置window.baz,看看您是否得到正確的結果,也是嘗試elclanrs'使用call()方法的建議,以確保它得到從foo叫的範圍。

編輯

你說的沒錯,的arguments[0]foo.bar類型是相同的;他們都是「功能」。我認爲困惑在於JavaScript將函數當作第一類對象來處理。

如果你熟悉如Java或C++,那麼你會想到,當你調用bar,它總是由一個foo具有baz屬性稱爲面向對象的語言;但是,JavaScript中並不是這種情況。任何函數都可以被任何對象調用,這意味着結果可能有意義。

elclanrs說,兩者之間的差異全在於.。比方說,我做了我自己的對象phew = {baz: 44}。我可以有效地從foo「偷」一種方法,如下所示:phew.myMethod = foo.bar。現在,phew知道bar中包含的指令,如果我撥打phew.myMethod(),我會得到44作爲我的結果,因爲phew正在調用該方法,並且phewbaz是44;沒關係其中該方法已定義!重要的是該方法說的做什麼bar說返回baz誰叫它。

所以,現在回到您的代碼,您打電話給arguments[0]()。它似乎應該是相同的,但因爲函數是第一類對象,所以當您將它作爲參數傳遞時,您真正傳遞的是一個名爲bar的函數。當您撥打arguments[0]()時,就像撥打bar()一樣,這與調用foo.bar()不同,就像它與調用phew.myMethod(),不同,即使它們全都是完全相同的功能

欲瞭解更多信息,請this SO post

+0

其實你沒有回答我的問題。我不明白的是'arguments [0]'id與'foo.bar'有什麼不同?兩者都返回相同的函數'function(){return this.baz; }'那麼爲什麼'arguments [0]()'使用全局對象而不是'foo.bar()'? – rkb

+0

'arguments [0]()'與'foo.bar()'不同,因爲它首先將arguments [0]賦值爲'function(){return this.baz; }'這不是對象'foo'的方法。而'foo.bar()'作爲'foo'的一個方法運行。 – rkb

+0

其實如果你把 console.log(foo.bar === arguments [0]) 這個匿名函數裏面顯示爲true。就像你寫兩個相同的函數一樣,它們將不相等。 – Tanmoy