为什么我在Javascript中丢失了这个上下文?

时间:2013-05-05 06:56:57

标签: javascript

我有这个简单的代码:

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()正在运行时, <{1}}对象中的b属性。

我错过了什么?

jsbin

3 个答案:

答案 0 :(得分:6)

我发现克罗克福德对其运作方式有很好的描述。 JavaScript中的函数可以用4种样式调用:

  1. “功能”风格
  2. “方法”风格
  3. “构造函数”样式
  4. “来电或申请”风格。
  5. 我可能会在那里得到错误的名字,但精神是一样的。如果你没有它,你肯定会得到“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”。

答案 1 :(得分: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的问题中的这个范围是窗口,它没有“b”,因此你得到一个“未定义的”。

答案 2 :(得分: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()调用。这就是为什么你需要使用Ihsan所展示的applythis技巧。