2013-09-23 33 views
1

這可能是新手入門的典型問題。我研究了一些類似的問題,但無法解釋我所看到的行爲。如何在函數調用中解析'this'關鍵字

下面的代碼應該說明我正在嘗試做什麼。我有2個對象MyObjectA和MyObjectB。

MyObjectB有一個簡單地記錄消息的方法echo。它將this.name添加到消息中,試圖知道誰在執行該方法。它還打印出this的值。

MyObjectA有一個名爲callAFunctionWithMessage的方法,它正是這樣做的。它接受一個消息和一個函數並調用它。

在全局範圍內,對象被實例化和調用。我看到的是this.nameundefined。當在瀏覽器中執行時,this的值爲DOMWindowObject,而在nodejs中執行時,則有一些類似大型基礎設施的對象。有人能幫助我對這種行爲有所瞭解嗎?鑑於MyObjectA正在調用echo,我預計'this'指向MyObjectA。

我也是,執行MyObjectB.echo('hello')其中this按預期指向MyObjectB。

function MyObjectA(name) { 
    this.name=name; 
} 

MyObjectA.prototype = { 
    name : "", 
    callAFunctionWithMessage: function (msg, callback) { 
     callback(msg); 
    } 
} 

function MyObjectB(name) { 
    this.name = name; 
    } 

MyObjectB.prototype = { 
    name :"", 
    echo: function(msg) { 
     var messageToPrint='[from '+this.name+']'+msg; 
     console.log(messageToPrint, " : " + this); 
    } 
} 

var a = new MyObjectA("ObjA"); 
var b = new MyObjectB("objB"); 

a.callAFunctionWithMessage('hello from A!', b.echo); 
// => [from result]hello from A! : [object Window] 

b.echo('hello!'); 
// => [from objB]hello! : [object Object] 

回答

3

當你這樣做:

a.callAFunctionWithMessage('hello from A!', b.echo); 

b.echo是越來越與全球範圍內(在您的案件窗口)傳遞的功能。所以this.name不會是對象a的名稱屬性,但它將是全局上下文的name屬性,因此您將其視爲未定義。您可以使用function.bind

a.callAFunctionWithMessage('hello from A!', b.echo.bind(a)); //now you set the callback with the context of b itself. 

在你的情況,而不是改變它的a本身的背景下,當調用回調方法裏面this將代表全球範圍內。

fiddle

或更改您設置的電流範圍內,以確保它沒有上下文的背景下,勢必它調用回調的方式。

MyObjectA.prototype = { 
    name : "", 
    callAFunctionWithMessage: function (msg, callback) { 
     callback.call(this, msg); 
    } 
} 

Fiddle

+0

謝謝你一起。通過回調這個回調是一個好主意。 –

2

當您通過b.echo當你經過它失去它的上下文中的函數回調。有幾條簡單的規則可以知道this的含義。

  1. 在對象上下文中,它將引用對象實例。
  2. 根據嚴格模式,在對象上下文外部,它將是全局對象(Window)或undefined
  3. 如果嚴格模式生效this不會自動解析爲全局對象。它將是undefined
1

this值將取決於如何功能調用改變,即它是在調用時給出什麼情況?唯一的例外是bound functions

我希望下面的例子將有助於您的理解,與MDN page for this

function foo() { 
    console.log(this); 
} 

var bar = { 
    'foo': foo, 
    'baz': function() {foo();} 
}; 

foo();  // -- logs the global object 
      // `foo` was called without context 
bar.foo(); // -- logs `bar` 
      // `foo` was called with context `bar` 
bar.baz(); // -- logs the global object 
      // `baz` (in context `bar`) called `foo` without context 
var x = bar.foo; 
x();   // -- logs the global object 
      // `x` was called without context, `x` is still `foo` 
x.call(bar); // -- logs `bar` 
      // `x` was called with context `bar` 
+0

我不認爲這回答了這個問題。相反,這提供了一個可能導致答案的難題。有可能。 –

+0

@WiktorZychla問題是'有人可以幫我對這種行爲有一些瞭解嗎?',這顯示了根據函數的調用方式發生了什麼,然後說了上下文,所以我不確定你的意思是什麼「難題」。我會嘗試通過添加額外的幾行文字來闡明我想要顯示的內容。 –

+0

謝謝..這非常有幫助!我認爲bar.baz()會指向這個酒吧,因爲foo是從酒吧中調用的。但我現在明白了。只有當它作爲其方法被調用時,上下文才被設置爲對象。 –