Подтвердить что ты не робот

Функции ES6 arrow все еще закрываются над "this", даже если они не используют его?

Я пытаюсь понять правила, когда this лексически привязана к функции со стрелкой ES6. Давайте сначала посмотрим на это:

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

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

Когда я создаю a new Foo(other), обратный вызов устанавливается на этом другом объекте. Обратный вызов - это функция стрелки, а this в функции стрелки лексически привязана к экземпляру Foo, поэтому Foo не будет собираться мусором, даже если я не буду ссылаться на ссылку Foo вокруг.

Что произойдет, если я сделаю это вместо этого?

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

Теперь я установил обратный вызов на nop, и я никогда не упоминаю this в нем. Мой вопрос: работает ли функция стрелки по-лексически привязана к this, сохраняя Foo до тех пор, пока other жив, или может Foo быть мусором, собранным в этой ситуации

4b9b3361

Ответ 1

Я задаю вопрос: ли функция стрелки все еще лексически привязана к этому, сохраняя Foo живым до тех пор, пока другой жив, или может ли Foo быть мусором, собранным в этой ситуации?

Что касается спецификации, функция стрелки имеет ссылку на объект среды, в котором она была создана, и этот объект окружения имеет this, а this ссылается на экземпляр Foo, созданный этим вызов. Поэтому любой код, основанный на том, что Foo не хранится в памяти, опирается на оптимизацию, а не на заданное поведение.

Оптимизация, сводится к тому, работает ли движок JavaScript, который вы используете, оптимизирует закрытие и может ли он оптимизировать закрытие в конкретной ситуации. (Это может предотвратить ряд вещей.) Ситуация такая же, как у "нормальных" функций:

function Foo(other) {
    var t = this;
    other.callback = function() { };
}

В этой ситуации функция закрывается в контексте, содержащем t, и поэтому теоретически имеет ссылку на t, которая, в свою очередь, хранит экземпляр Foo в памяти.

Что теория, но на практике современный движок JavaScript может видеть, что t не используется закрытием и может оптимизировать его, если это не приведет к наблюдаемому побочному эффекту. Независимо от того, будет ли это делать, и если да, то, когда это полностью зависит от двигателя.

Поскольку функции стрелок действительно являются лексическими замыканиями, ситуации в точности аналогичны, поэтому вы можете ожидать, что движок JavaScript сделает то же самое: оптимизируйте его, если только он не вызывает побочный эффект, который можно наблюдать. Тем не менее, помните, что функции стрелок очень новые, поэтому вполне возможно, что у двигателей не так много оптимизации вокруг этого (без каламбура).

Версия V8 в Chrome (я использую Chrome 48.0.2564.116 64-bit) делает в настоящее время: это я использовал Chrome в режиме, который позволяет принудительно собирать мусор ( google-chrome --js-flags="--expose-gc") и выполнил следующее:

"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 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);
}