【问题标题】:Why do I lose the context of this in Javascript?为什么我会在 Javascript 中丢失 this 的上下文?
【发布时间】:2013-05-05 06:56:57
【问题描述】:

我有这个简单的代码:

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) 产生未定义。 (虽然我期待“22”作为结果)

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

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

它确实有效。

但我的问题是:

  • 我在什么阶段失去了上下文?

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

我错过了什么?

jsbin

【问题讨论】:

  • 当您将其称为 f() - JavaScript 方法是“未绑定函数”(也就是说,与其他语言中的方法不同,它们是与特定对象/实例相关联),它是在调用时确定this 的调用站点。 (当然,请参阅Function.bind 或等效仿真。)
  • 你一经过o.f1就会丢失它。如果您执行var x = o.f1 并调用x(),则f1 不再绑定。
  • @Blender 我知道。但为什么 this 不涉及 o2 ?这是我不明白的
  • @RoyiNamir f() 大致相当于window.f = f; window.f() 在它如何影响被调用函数内的this 方面。 Here are the gory details.
  • @RoyiNamir:为什么要这样做?它是不受约束的。调用它不会神奇地将它绑定到当前上下文。

标签: javascript


【解决方案1】:

我发现 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”。

【讨论】:

    【解决方案2】:

    如果你这样做,

    函数将在 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”,因此您得到一个“未定义”。

    【讨论】:

      【解决方案3】:

      检查这个测试:

      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() 调用。这就是为什么你需要使用apply 或Ihsan 展示的this 技巧。

      【讨论】:

        猜你喜欢
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-28
        • 2015-09-20
        • 1970-01-01
        • 2016-05-03
        相关资源
        最近更新 更多