Почему setTimeout по-прежнему вызывает обратный вызов после удаления объекта - PullRequest
3 голосов
/ 31 марта 2020

У меня был вопрос, и я подумал, что если вы вызвали setTimeout из объекта, то delete d объекта, будет ли по-прежнему вызываться обратный вызов setTimeout?

Очевидно, да.

var container = {
    timer: { // the object to be deleted
        start: function() {
            console.log('start');
            setTimeout(this.end, 2000);
        },
        end: function() {
            console.log('end');
        },
    },

    timerStart: function() { 
        this.timer.start();
        setTimeout(this.timerDelete, 1000);
    },

    timerDelete: function() {
        console.log(delete this.timer);
        console.log('deleted timer');
    },
};

После вызова container.timerStart(); я получаю следующее:

> container.timerStart();
  start
< undefined
  true
  deleted timer
  end

Следовательно, показывая, что объект container.timer был успешно удален, но также container.timer.end был также вызван после container.timer был удален Я понимаю, что delete только удаляет ссылку, и как только все ссылки на объект удаляются, он удаляется из памяти, но означает ли это, что setTimeout также хранит ссылку на его обратный вызов?

По сути мои вопросы:

  1. Действительно ли container.timer действительно удалено?
  2. Почему setTimeout обратный вызов container.timer.end все еще выполняется?
  3. Как работает setTimeout на самом деле работать со ссылкой на это поведение?

Любые отзывы или ресурсы для чтения с благодарностью. Спасибо!

1 Ответ

4 голосов
/ 31 марта 2020

означает ли это, что setTimeout также хранит ссылку на свой обратный вызов?

Да, именно это и происходит. Это похоже на:

const obj = {
  fn: () => console.log('fn')
};
const fn = obj.fn;
delete obj.fn;
fn();

Действительно ли container.timer удален?

В том смысле, что container больше не имеет свойства timer, да, но функция timer все еще существует, поскольку setTimeout по-прежнему содержит ссылку на нее.

Почему обратный вызов setTimeout container.timer.end все еще выполняется?

Потому что он тоже был поставлен в очередь в setTimeout. start запускается немедленно, что

setTimeout(this.end, 2000);

, поэтому setTimeout сохраняет ссылку на функцию в this.end и вызывает ее через пару секунд.

Что-то будет только мусор, собранный один раз ничто больше не содержит ссылки на него (кроме, возможно, циклической ссылки). Если что-то хранится в замыкании или в обратном вызове, и на обратный вызов все еще можно ссылаться, это не будет G C 'd, по крайней мере, до тех пор, пока ничто больше не сможет ссылаться на него.

...