闭包和这个澄清是什么?

4

我遇到了一个与this上下文有关的小问题:

在JavaScript中,this总是指向我们正在执行的函数的“所有者”,或者更确切地说,指向一个函数是其方法的对象。

因此,这段代码:

var o={

  f:function ()
     {
       console.log(this); //the owner of the function is `o`
     }
}

console.log(o.f()) // this shows the `o` as this

一切正常。

那么,这段代码是为什么而存在的呢?

var o = {
    f: function ()
    {
        return function ()
        {
            console.log(this);
        }
    }
}
console.log(o.f()())

显示this是全局对象/窗口?

o.f()返回一个函数,然后我执行它。但仍然将Hoster对象显示为o,那么为什么它显示Hoster为window


3
你返回的匿名函数属于什么/谁?没有人...意味着是window对象。你可以将this绑定到返回的函数上,这样this的值将始终指向o。你最后一行的技术含义是:console.log((function () { console.log(this); }).bind(this)()); - Ian
在这里,您可以找到一些关于闭包如何工作的很好的答案,这可能有助于理解。 - excentris
有关JavaScript中this如何工作的更详细解释,请参见:https://dev59.com/c2Yr5IYBdhLWcg3wuciw#13441628 - slebetman
5个回答

4

this 的值由调用该函数的对象决定,而不是函数声明的位置。

例如,如果您执行以下操作:

var f = o.f;
console.log(f());

如果你看到了this,那么它也是一个窗口(window)。

你还可以做这样的事情:

var o2 = { f: o.f };
console.log(o2.f());

这里的this指的是o2对象,而不是o对象。

在你的情况下,o.f返回一个函数,但你没有引用对象来调用它。在这种情况下,被调用的函数中的this指向全局对象(在浏览器中是window)。

如果你想保留this指针,你需要在闭包中捕获它,像这样:

var o = {
    f: function ()
    {
        var self = this;
        return function ()
        {
            console.log(self);
        }
    }
}
console.log(o.f()())

然后你将拥有正确的对象引用,无论它被称呼为什么。


2

不是的。返回的函数只是一个函数,没有托管在任何对象上(这使得this默认为全局对象)。可以将双重调用视为:

var temp = o.f();
temp();

不要使用“所有者上下文”这个隐喻(它经常失效),最好参考MDN介绍的this关键字。仅在您在对象上调用方法时,“所有者”对象解释才有效 - 一旦您将函数传递给其他地方(例如回调、return或分配),它就会失去其上下文。


2

this是由函数的调用方式决定的,而不是由其存储位置决定的。

o.f()之所以有效,是因为您在o的上下文中调用了f()。如果您将该函数复制到另一个对象中,则this会改变。

例如:

var x = {
  a: o.f
};

console.log(x.a()); // logs x, not o.  because the "context" is x

在您的第二个示例中,o.f()返回一个函数,然后在"无上下文"的情况下运行。这将使"上下文"设置为window

1
答案很简单。您正在返回一个闭包,随后在窗口范围内评估它。如果您没有返回该函数,就不会有这个问题。
解决方案:
var o = {
  f: function() {
    return function() { console.log(this); }
  }
};
console.log(o.f().apply(o, []));

将闭包的所有权从空(= window)转移到o

我知道apply/call/bind可以改变上下文,但那不是我的问题。 - Royi Namir
我在第一段回答了你的问题:你正在返回一个未绑定的闭包。 - Sébastien Renauld
不需要传递一个空的参数数组到 apply,你可以直接什么都不传 :-) - Bergi
@Bergi:没错,不过差别非常微小 :-) - Sébastien Renauld

1
当一个函数没有所有者时,获取本地上下文会回退到全局上下文,因为真正的上下文是未定义的。如果真正的上下文是null,则也会执行相同的操作。
在非严格模式下,所有这些都是正确的!
在严格模式下,获取本地上下文不会回退到其他任何内容。上下文保持不变,也就是说,在没有所有者的情况下,上下文是undefined。这非常重要,请注意。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接