11

我有这个简单的代码:

var o = {
    a: 1,
    b: 2,
    f1: function ()
    {
        alert(this.b);
    }
}

var o2 = {
    a: 11,
    b: 22,
    f2: function (j)
    {
        j();
    }
}

但是运行这段代码:

o2.f2(o.f1)产生undefined。(虽然我期待“22”作为结果)

现在,我知道上下文已经到了某个地方。因此,如果我将代码更改o2为:

 f2: function (j)
    {
        j.apply(this);
    }

它确实有效。

但我的问题是:

  • 我在哪个阶段失去了上下文?

我不明白:j()运行时,对象中一个b属性o2

我错过了什么?

jsbin

4

3 回答 3

7

我发现 Crockford 对它的工作方式有很好的描述。JavaScript 中的函数可以以 4 种样式调用:

  1. “功能”风格
  2. “方法”风格
  3. “构造函数”风格
  4. “调用或应用”样式。

我可能在那里弄​​错了确切的名字,但精神是一样的。如果你没有这本书,那么你绝对应该得到这本书“JavaScript: The Good Parts”。

所以无论如何-关于你的问题。关键是“this”的值取决于您使用的样式。

// function invocation style, 
var f = function() { console.debug(this); }
f(); // "this" is bound to the global object.

// "method" invocation style
var obj = {
    f: function() { console.debug(this); }
};

obj.f(); // "this" is bound to "obj", the object on which the function was invoked

// so important bit is :

var f = obj.f;
f(); // "this" is global object
obj.f() // "this" is obj

在您的示例中,由于调用函数的方式,您正在丢失“this” 。

于 2013-05-05T08:02:12.967 回答
1

如果你这样做如下,

函数将在 o2 上下文中调用

var o2 = {
    a: 11,
    b: 22,
    f2: function (j){
      this.temp = j;
      this.temp();
    }
};

这些也将起作用:

f2: function (j){
      j.apply(this);
}

f2: function (j){
      j.apply(o2);
}

否则,您就像脱离上下文的普通函数一样调用它。

j 已脱离其上下文,并且您没有对其进行任何棘手的关闭(这不是您的意图),因此要使“this”在其中工作,您需要一个范围。您对 j 的问题中的 this 范围是窗口,其中没有“b”,因此您得到“未定义”。

于 2013-05-05T07:24:17.837 回答
0

检查这个测试:

o.f1(); // alerts 2

var f3 = o.f1; // (*)

f3(); // alerts undefined

o2.f2(f3); // alerts undefined

f3.apply(o2); // alerts 22

(*)我意识到,当您将函数作为参数传递时,上下文丢失的方式与上面代码中所指出的丢失方式完全相同。

正在发生的事情j = arguments[0] = o.f1,此时你失去了上下文。

当将函数作为参数传递时,您只是将内存中的引用传递给该函数。如果不绑定上下文,您将无法通过简单的j()调用。这就是为什么你需要使用applythisIhsan 展示的技巧。

于 2013-05-05T07:43:19.520 回答