2010-06-15 107 views
11

我看到下面這個site解釋的例子,認爲兩個答案都是20而不是返回的10。他寫道,逗號和任務都會返回一個值,而不是參考。我不太明白這是什麼意思。爲什麼賦值運算符返回一個值而不是引用?

我知道它與將變量傳遞到函數或方法有關,即原始類型通過引用傳入值和對象,但我不確定它在這種情況下如何應用。我也理解關於上下文和'this'的價值(在從stackoverflow的幫助後),但我認爲在這兩種情況下,我仍然會調用它作爲一個方法,foo.bar()這將意味着foo是上下文但它似乎都導致了一個函數調用bar()。

這是什麼,它是什麼意思?

var x = 10; 
var foo = { 
    x: 20, 
    bar: function() {return this.x;} 
}; 

(foo.bar = foo.bar)();//returns 10 
(foo.bar, foo.bar)();//returns 10 
+1

'(foo.bar = foo.bar)()'是如此** **參加我的面試問題清單! ^。^ – 2010-06-15 21:18:34

+0

@Ben:不是'(foo.bar,foo.bar)()'? ;-)我的意思是,如果你想深奧... – 2010-06-15 23:21:40

+9

@Ben - 讓我知道你的工作對象,所以我不會犯錯採訪:) – screenm0nkey 2010-06-16 09:12:12

回答

11

它不具有值與參考文獻進行,它與this值做(因爲你懷疑)。在JavaScript中,this設置爲,完全由決定,函數如何被調用,而不是它被定義的地方。您可以設置三種方式之一this值:

  1. 呼叫通過使用屬性訪問符號的對象屬性的功能,可以通過點表示法(obj.foo())或括號表示法(obj["foo"]())。
  2. 呼叫通過使用with語句中的對象屬性的功能(其實只是#1變體,但值得呼喚獨立,特別是因爲它不是很明顯從源代碼)
  3. 利用的applycall功能函數實例。

在上面你的例子,你沒有做任何這些,所以你最終調用該函數使用默認值this,全局對象,所以x來自那裏,而不是從你的foo對象。這裏是另一種方式來思考一下該代碼是這樣做的:

var f = foo.bar; // Not calling it, getting a reference to it 
f();    // Calls the function with `this` referencing the global object 

如果你不直接使用屬性實際撥打電話(而不是檢索屬性的,然後製作與呼叫),this處理不起作用。

+1

它與引用類型有關,因爲逗號運算符和簡單賦值在內部都使用'GetValue',這會導致引用的*基對象*丟失。 – CMS 2010-06-15 17:51:42

+0

@CMS:對,這是我描述的行爲背後的基本機制。我不認爲需要鑽研那些深度。 (我沒有談論[[Call]]方法或[[Scope]]屬性,或者:-))。 – 2010-06-15 18:11:51

+0

@TJ&CMS - 隨時按照技術要求進行回覆。如果我不明白,我會問你一些問題。 另外CMS的迴應對我來說更有意義,因爲我仍然不明白爲什麼(foo.bar = foo.bar)()不等同於foo.bar()。 在你的例子中,你只使用f = foo.bar,這對我來說很有意義,因爲f()是一個函數調用,但是如果它是f.bar = foo.bar,那麼對我來說就等同於f.bar(),這意味着f將'this' – screenm0nkey 2010-06-15 20:50:05

2

你誤會了。

這兩個示例都返回windowx屬性,因爲它們沒有在foo上直接調用。

函數內關鍵字this的值取決於調用該函數的上下文。

在一個普通的函數調用中(例如,myFunc()),this將是全局對象,它通常是window
在對象方法調用中(例如,foo.bar()),this將是調用函數的對象。 (在這種情況下,foo

您可以通過調用myFunc.call(context, arg1, arg2)myFunc.apply(context, argArray)明確地設置上下文。

這兩個例子都是對錶達式的正常調用,其值爲foo.bar。因此,thiswindow

它們等同

var func = (some expression); 
func(); 
+0

我明白你寫的所有內容,包括你的例子但在我的頭(foo.bar = foo.bar)仍然等於foo.bar()而不是bar(),因爲你告訴我(我知道這是正確的)。你們,CMS和TJ都給了我很好的迴應,但我需要讓自己的頭腦清醒,因爲我有點簡單。 – screenm0nkey 2010-06-15 21:18:45

8

您應該瞭解內部Reference Type的工作原理。

注意:這不是一種語言數據類型,是一種處理引用的內部機制。

的引用是由兩個元件時,基礎對象屬性名的。

在你的例子中,foo.bar引用看起來像這樣。

// pseudo-code 
foo.bar = { 
    baseObject: foo, 
    propertyName: 'bar' 
} 

兩者,所述comma operatorsimple assignment,依靠獲取屬性名的值,即會導致丟失基礎對象,由於被返回一個值(這是通過內部GetValue操作製造) 。

這是內部GetValue操作是如何工作的:

// pseudo-code 
GetValue(V) : 
    if (Type(V) != Reference) return V; 

    baseObject = GetBase(V); // in your example foo 
    if (baseObject === null) throw ReferenceError; 

    return baseObject.[[Get]](GetPropertyName(V)); 
    // equivalent to baseObject[v.PropertyName]; 

正如你看到的,一個返回,所以原來的基準丟失。

編輯:的關鍵在於理解爲什麼(foo.bar = foo.bar)();不等同於foo.bar();依賴於Simple Assignment操作,讓我們來看看算法:

 
11.13.1 Simple Assignment (`=`) 
The production `AssignmentExpression` : 
       `LeftHandSideExpression` = `AssignmentExpression` 

is evaluated as follows: 

1. Evaluate LeftHandSideExpression. 

2. Evaluate AssignmentExpression. 

3.Call GetValue(Result(2)). 

4.Call PutValue(Result(1), Result(3)). 

5.Return Result(3). 

基本上當你(foo.bar = foo.bar)實際分配(第4步。)不起作用,因爲PutValue只會獲得引用的值,並會將其放回,並具有相同的基礎對象。

的關鍵是,賦值運算符返回(步驟5)在步驟3和正如我說得到的值之前的GetValue僞碼,此內部方法返回一個其沒有按」 t確實有一個基本對象

+0

這會教我。我對T.J.說。 Crowder將它視爲技術性的,但現在我無法理解它。如果沒有問題,我需要考慮你寫的內容並回復給你。 – screenm0nkey 2010-06-15 21:13:05

+0

@尼克,當然,想一想,我們正在處理一個完全抽象的類型,它存在於純粹用於*說明目的*的規範中。這可能會讓它有點難以喘口氣。閱讀關於它和'GetBase','GetPropertyName'和'GetValue'內部方法,然後我們可以更進一步,我可以向您解釋如何使用Reference類型在設置函數時設置'this'值呼叫。 – CMS 2010-06-15 21:27:54

+0

謝謝你。你對JavaScript的理解是難以置信的。我會拿走你所說的話,並嘗試去理解它,並進行一些研究。在這一點上,我必須授予我給TJ的正確答案,並不是因爲他的回答比所有答案都好,而是因爲我必須選擇答案。我會+1你和其他人,因爲我認爲我們都是很好,有用的答案。再次感謝你的幫助。 – screenm0nkey 2010-06-16 10:00:33

2

這可能有助於將點運算符看作與with語句類似的行爲。當您運行foo.bar(),結果是一樣一樣的,如果你跑:

with (foo) { 
    bar(); // returns 20 
} 

這將foo覆蓋在全局對象之上運行bar功能,允許它找到xfoo,因此回報20.

如果不立即撥打bar,不過,因爲在(foo.bar = foo.bar),你反而得到:

with (foo) { 
    bar; // returns "bar" itself 
} 

然後將結果傳遞出括號,產生一個如<reference to bar>()這樣的中間語句,它沒有點運算符,因此沒有with語句,因此沒有訪問foo,只能訪問全局值x

(點運算符不實際上轉換爲with說法,當然,但行爲是相似的。)

+0

謝謝你 - 幫助我很多。之前並沒有真正使用過這個聲明,但它給了我一些研究成果。所以在這個例子中(nick.foo.low.man = foo.man.tan.bar)()它將與 一樣具有(foo.man.tan){ bar; //返回「bar」本身 } – screenm0nkey 2010-06-16 09:51:34

相關問題