{-6ren">
gpt4 book ai didi

javascript - 即使不使用 ES6 箭头函数,它们是否仍然在 "this"上关闭?

转载 作者:行者123 更新时间:2023-12-03 01:25:24 24 4
gpt4 key购买 nike

我正在尝试了解何时 this 的规则词法绑定(bind)在 ES6 箭头函数中。我们先来看看这个:

function Foo(other) {
other.callback = () => { this.bar(); };

this.bar = function() {
console.log('bar called');
};
}

当我构建一个 new Foo(other) ,在该其他对象上设置回调。回调是一个箭头函数, this箭头函数在词法上绑定(bind)到 Foo例如, Foo即使我不保留对 Foo 的任何其他引用,也不会被垃圾收集大约。

如果我这样做会发生什么?
function Foo(other) {
other.callback = () => { };
}

现在我将回调设置为 nop,我从未提及 this在里面。 我的问题是:箭头函数是否仍然在词法上绑定(bind)到 this ,保持 Foo活到 other还活着,或者 Foo在这种情况下被垃圾收集?

最佳答案

My question is: does the arrow function still lexically bind to this, keeping the Foo alive as long as other is alive, or may the Foo be garbage collected in this situation?


就规范而言,箭头函数具有对创建它的环境对象的引用,并且该环境对象具有 this。 ,以及 thisFoo该调用创建的实例。所以任何依赖于 Foo 的代码不保存在内存中依赖于优化,而不是指定的行为。
再优化,归结为你使用的JavaScript引擎是否对闭包进行了优化,具体情况下能否对闭包进行优化。 (有很多事情可以阻止它。)就像这个带有传统函数的 ES5 示例一样:
function Foo(other) {
var t = this;
other.callback = function() { };
}
在这种情况下,函数关闭包含 t 的上下文。 ,所以理论上,有一个引用 t这反过来又保留了 Foo内存中的实例。
这是理论,但在实践中现代 JavaScript 引擎可以看到 t闭包不使用它,并且可以优化它,前提是这样做不会引入可观察到的副作用。是否会,如果会,何时会,完全取决于引擎。
由于箭头函数确实是词法闭包,因此情况完全相似,因此您希望 JavaScript 引擎做同样的事情:优化它,除非它会导致可以观察到的副作用。也就是说,请记住箭头函数是 非常新 ,所以很可能引擎还没有对此进行太多优化(没有双关语)。
在这种特殊情况下,我在 2016 年 3 月(在 Chrome v48.0.2564.116 64 位中)和 2021 年 1 月(Brave v1.19.86 基于 Chromium v​​88.0.4324)编写此答案时使用的 V8 版本。 96) 优化关闭。如果我运行这个:

"use strict";
function Foo(other) {
other.callback = () => this; // <== Note the use of `this` as the return value
}
let a = [];
for (let n = 0; n < 10000; ++n) {
a[n] = {};
new Foo(a[n]);
}
// Let's keep a Foo just to make it easy to find in the heap snapshot
let f = new Foo({});

log("Done, check the heap");
function log(msg) {
let p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}

然后在 devtools 中拍摄堆快照,我看到 Foo 的预期 10,001 个实例在内存中。如果我运行垃圾收集(现在你可以使用垃圾桶图标;在早期版本中,我必须使用特殊标志运行,然后调用 gc() 函数),我仍然看到 10,001 Foo实例:
enter image description here
但如果我更改回调使其不引用 this :
      other.callback = () => {  }; // <== No more `this`

"use strict";

function Foo(other) {
other.callback = () => {}; // <== No more `this`
}
let a = [];
for (let n = 0; n < 10000; ++n) {
a[n] = {};
new Foo(a[n]);
}
// Let's keep a Foo just to make it easy to find in the heap snapshot
let f = new Foo({});

log("Done, check the heap");
function log(msg) {
let p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}

并再次运行该页面,我什至不必强制垃圾收集,只有一个 Foo内存中的实例(我放在那里以便在快照中查找):
enter image description here
我想知道是不是因为回调完全为空而允许优化,并惊喜地发现它不是:Chrome 很高兴保留部分闭包,同时放开 this ,如此处所示:

"use strict";
function Foo(other, x) {
other.callback = () => x * 2;
}
let a = [];
for (let n = 0; n < 10000; ++n) {
a[n] = {};
new Foo(a[n], n);
}
// Let's keep a Foo just to make it easy to find in the heap snapshot
let f = new Foo({}, 0);
document.getElementById("btn-call").onclick = function() {
let r = Math.floor(Math.random() * a.length);
log(`a[${r}].callback(): ${a[r].callback()}`);
};
log("Done, click the button to use the callbacks");

function log(msg) {
let p = document.createElement('p');
p.appendChild(document.createTextNode(msg));
document.body.appendChild(p);
}
<input type="button" id="btn-call" value="Call random callback">

尽管回调存在并且引用了 x , Chrome 优化 Foo实例远。

您询问了关于 this 的规范引用在箭头函数中解决:该机制在整个规范中传播。每个 environment (如调用函数创建的环境)有一个 [[thisBindingStatus]]内部插槽,即 "lexical"用于箭头功能。在确定 this 的值时,内部操作 ResolveThisBinding 使用,它使用内部 GetThisEnviroment 查找具有 this 的环境的操作定义。当进行“正常”函数调用时, BindThisValue 用于绑定(bind) this如果环境不是 "lexical",则用于函数调用环境。所以我们可以看到解析 this从箭头函数内部就像解析变量一样:检查当前环境是否有 this绑定(bind)并且没有找到一个(因为调用箭头函数时没有绑定(bind) this),它转到包含环境。

关于javascript - 即使不使用 ES6 箭头函数,它们是否仍然在 "this"上关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35813344/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com