2010-04-28 111 views
1

在使用JavaScript對象時,我一直在閱讀關於'this'關鍵字的很多文章,但我仍然有些困惑。我很高興編寫面向對象的Javascript,並且通過引用完整的對象路徑來解決'this'問題,但我不喜歡這個事實,我仍然覺得'this'混亂。對JavaScript的'this'仍然感到困惑

我找到了一個很好的答案here幫助我,但我仍然不是100%確定。所以,在這個例子上。下面的腳本是從test.html的鏈接與<script src="js/test.js"></script>

if (!nick) { 
    var nick = {}; 
} 

nick.name= function(){ 
    var helloA = 'Hello A'; 
    console.log('1.',this, this.helloA); 

    var init = function(){ 
     var helloB = 'Hello B'; 
     console.log('2.',this, this.helloB); 
    } 

    return { 
     init: init 
    } 
}(); 

nick.name.init(); 

什麼樣的期望看到的是

1. Object {} nick.name, 'Hello A' 
2. Object {} init, 'Hello B' 

但是我所得到的是什麼?

1. Window test.html, undefined 
2. Object {} init, undefined 

我想我明白了一些什麼發生的事情,但如果有人在那裏它解釋了我,我不會介意。

此外,我不完全確定爲什麼第一個'console.log'被調用?如果我刪除調用init函數//nick.name.init()螢火蟲仍然輸出1. Window test.html, undefined。這是爲什麼?爲什麼在html頁面加載時,由窗口對象調用nick.name()?

非常感謝

回答

3

而且,我不完全知道爲什麼第一「的console.log」被調用呢?

nick.name = function(){ 
    // ... 
}(); 

在這裏定義一個函數,立即(因此())調用它,它的返回值({init: init})分配給nick.name

所以執行是:

  1. 創建一個變量nick如果沒有一個非虛假值已經
  2. 創建一個匿名函數針對這樣...
  3. (因爲該函數是在全球範圍內爲方法執行,而不是window)使用console.logthis在它自己的範圍稱爲helloA
  4. 輸出數據的可變含有「1」(原樣), ,並且this.helloAwindow.helloA,它不存在。
  5. 定義了一個名爲init
  6. 函數會返回一個被分配到nick.name
  7. 然後調用nick.name.init()其執行的name背景下init函數的對象。
  8. 這定義helloB
  9. 然後console.logs 「2」(這是),thisname)和this.helloBnick.name.helloB - 這不存在)

所以你得到的第一個輸出從console.log('1.',this, this.helloA);

我認爲你的主要問題是你很容易混淆this.foo(在調用方法的對象上的屬性)與變量作用域(函數可用的變量)

+0

我沒有說它在'lowman'的上下文中定義了'helloB'。它在'lowman'的**範圍**中定義。存在於給定範圍內的變量與對象上的屬性不同。 – Quentin 2010-04-28 12:20:54

+0

非常感謝你的幫助David。我已經在早上創造了一些例子,我想我正在慢慢獲得它。 – screenm0nkey 2010-04-29 12:04:19

2
  1. this是基於每個功能的基礎當函數調用時定義。當你調用一個函數o.f(),this將是o內的函數,並且當你調用它爲f(),this將是全局對象(對於瀏覽器來說,這是窗口)。 您寫的nick.name = function(){...}();和右手部分的形式爲f(),因此Window

  2. var foo = bar;定義了一個局部變量。它可能不會被作爲this.foo訪問(當然,除非在全球範圍內,但這很愚蠢)。要定義一個成員,你通常會寫this.foo = bar;

+0

維克多,這是很好的答案,謝謝。你知道窗口對象爲什麼叫這個函數嗎? – screenm0nkey 2010-04-28 11:39:40

+0

確切地說,當你自己調用一個函數(而不是成員)時,'this'是全局對象,對於Web瀏覽器來說,它是'Window'。 – 2010-04-28 11:52:30

+0

再次感謝Victor。非常感激。 – screenm0nkey 2010-04-29 12:45:56

2

如果您將this作爲函數而不是變量來考慮,這會簡單得多。本質上,this是一個返回當前「執行上下文」的函數,也就是當前函數被「應用」到的對象。例如,請考慮以下

function t() { console.log(this)} 

這將返回不同的結果,這取決於你怎麼稱呼它

t() // print window 

bar = { func: t } 
bar.func() // print bar 

foo = { x: 123 } 
t.apply(foo) // print foo 
+0

美孚在這裏不是一個功能,所以它不會有應用方法。我認爲你的意思是t.apply(foo)。 apply方法讓我們在調用函數時明確地定義執行上下文(this的值)。 (另請參閱Function.call) JavaScript在這種意義上的靈活性可能是一個非常強大的工具,但它也是一個非常令人沮喪的來源,特別是在您開始考慮之前! – adamnfish 2010-04-28 11:31:07

+0

感謝您的答覆stereofrog。我可以問一下foo.apply(t)嗎?那是一個錯誤嗎?應該是t.apply(foo)//打印foo? 非常感謝 – screenm0nkey 2010-04-28 11:45:05

+0

謝謝stereofrog :) – screenm0nkey 2010-04-29 12:46:53

1

這是你的代碼做什麼:

  • 它創建一個對象,分配給變量nick
  • 它創建一個匿名函數。
  • 它調用函數(在窗口範圍內)。
  • 它將返回值(包含init屬性的對象)分配給對象的name屬性。
  • 它從init屬性(它是一個方法委託)中獲取值,並調用該方法。

匿名函數做到這一點:

  • 它聲明瞭一個名爲helloA一個局部變量和一個字符串分配給它。 (創建局部變量不會將其作爲屬性添加到當前對象。)
  • 它記錄了this(窗口)和helloA屬性(不存在)。
  • 它創建一個匿名函數並分配給本地變量init
  • 它使用屬性init和本地變量init創建一個對象。

分配給init屬性的匿名函數做到這一點:

  • 它聲明瞭一個名爲helloB一個局部變量和一個字符串分配給它。 (創建本地變量不將其添加爲屬性設置爲當前對象。)
  • 它記錄this(從name屬性,而不是nick變量的對象),並且helloB屬性(它不存在) 。
+0

所以我應該使用這個關鍵字時應用變量對象,即this.helloA或這樣做使私人varaibles成爲公共? – screenm0nkey 2010-04-28 12:11:35

+0

@Nick:這取決於當前的上下文。如果上下文是一個對象,則可以使用'this'關鍵字來訪問該對象。如果它是默認上下文(窗口),您將爲窗口對象添加屬性,從而使它們成爲全局/公共。 – Guffa 2010-04-28 12:57:37

+0

感謝您的幫助Guffa :) – screenm0nkey 2010-04-29 12:49:27