为什么我会丢失Javascript中的上下文?

为什么我会丢失Javascript中的上下文?,javascript,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)产生未定义的结果。(我希望结果是“22”) 现在,我知道上下文已经到了某个地方。因此,如果我将o2中

我有一个简单的代码:

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
属性

我错过了什么


如果您按照以下方式操作

函数将在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脱离了它的上下文,您没有对它进行复杂的闭包(这不是您的意图),所以要使“这个”在其中工作,您需要一个范围。您问题中j的范围是窗口,窗口中没有“b”,因此您会得到一个“未定义的”。

检查此测试:

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
技巧。

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

  • “功能”风格
  • “方法”风格
  • “构造函数”风格
  • “调用或应用”样式
  • 我可能把确切的名字弄错了,但精神是一样的。如果你没有《JavaScript:好的部分》这本书,你肯定会得到它

    所以不管怎样,请回答你的问题。关键是“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”。

    当您将其称为
    f()
    -JavaScript方法是“未绑定函数”(也就是说,与其他语言中的方法不同,它们不与特定对象/实例相关联)调用时,由调用站点决定此。(当然,请参阅或等效的仿真。)您一绕过
    o.f1
    就会丢失它。如果您执行
    var x=o.f1
    并调用
    x()
    f1
    将不再绑定。@Blender我知道。但是为什么
    这个
    不是关于
    o2
    ?这是我不知道的understand@RoyiNamir
    f()
    大致相当于
    window.f=f;window.f()@罗伊纳米尔:为什么要这么做?它是未绑定的。调用它不会神奇地将它绑定到当前上下文。