将对象分配给未定义和删除之间



我正在阅读JavaScript Ninja的秘密,并遇到了一个编码示例:

var ninja = {
    yell: function(n){
        return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
    }
};
var samurai = { yell: ninja.yell };
//var ninja = {};
//delete ninja;
samurai.yell(4);

如果我删除第二个评论行,则samurai.yell(4)运行良好,我理解它,因为samurai仍然对ninja.yell最初引用的函数的引用,delete已删除。

但是,如果我运行第一个评论行,则samurai.yell(4)会出现错误。

有人可以解释引擎盖下发生的事情吗?

我以为如果将ninja分配为undefined,将创建新的引用并链接到ninja,原始引用仍然存在,并且由于samurai仍然对该功能有参考,垃圾收集将不会出现,并且将其删除在内存中。

var ninja = {
yell: function(n){
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
}
};
var samurai = { yell: ninja.yell };
var ninja = {};
//delete ninja;
samurai.yell(4);

var ninja = {};将声明一个名为ninja

的变量

由于忍者已被重新定义,并且新对象没有任何名为 yell与之关联的函数,因此下一行samurai.yell(4);将丢失错误。

说明:

一开始,ninja

var ninja = {
    yell: function(n){
        return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
    }
};

这里的忍者内部有一个函数yell,可以称为。

当您更改其价值为

ninja = {};

旧值(与功能一起)被新值删除和覆盖。

因此,当您致电

samurai.yell(4);

它进入{ yell: ninja.yell };,由于新的ninja没有yell功能,因此会引发错误

正如我在评论中所说的那样,这都是关于关闭的工作方式:

var bar = 1;
var foo = function() { console.log(bar); } // closes over `bar`
foo(); // closed-over `bar` reference: 1
bar = 2;
foo(); // closed-over `bar` reference reflects the update: 2
delete bar;
foo(); // closed-over `bar` still references the same location,
       // even when current context no longer has it

您通常不会看到delete的示例,但是正是这种机制使其可作为私人变量的替代者有用:

var foo = (function() {
  var bar = 1;
  return function() {
    console.log(bar);
  };
})();
foo();            // closed-over `bar`: 1 - even though:
console.log(bar); // Uncaught ReferenceError, as
                  // `bar` is not available in local context

是的,您正确理解了它,但真正的原因是GC力学。

他们正在传递对功能本身ninja.yell的引用。这是因为垃圾收集机制 - 直到任何参考都活着,将不会收集此功能。

在这种特殊情况下,我们正在抓取对ninja.yell的引用,即使我们删除最初包含此功能的对象,也不会收集垃圾。

大多数情况下,这种行为是不需要的,这就是为什么人们通常避免delete操作员。

我检查了@MRID和 @amadan的答案,并思考了一下,我想我想出了这一点,并提出了一个更简单的答案,我的问题中的解释并不完全正确。

如果我不使用第一个评论行,

var ninja = {};

我将忍者分配给一个空对象,因此,我尝试运行" samurai.yell(4);",我会遇到错误。原因是因为 samurai 试图通过其"示波链"找到 ninja (即一些闭合魔法,它确实找到了它,但是当它试图找到它时如果 ninja 具有属性 yell ,它已经消失了,因此错误。这意味着它仍然可以运行该函数),当该匿名函数试图运行ninja.yell()时,它找不到了,因此错误。

解决此问题的一种方法当然是使用this

var ninja = {
    yell: function (n) {
        return n > 0 ? this.yell(n-1) + "a" : "hiy";
    }
};
var samurai = { yell: ninja.yell };
var ninja = {};
samurai.yell(4);

另一种方法是使用命名函数表达式

var ninja = {
    yell: function foo(n) {
        return n > 0 ? foo(n-1) + "a" : "hiy";
    }
};
var samurai = { yell: ninja.yell };
var ninja = {};
samurai.yell(4);

一切都应该工作。

如果我不使用第二条评论行,

delete ninja;

我实际上什么都没做。 delete 仅用于对象的"删除"属性(您永远无法删除JavaScript中的任何内容,垃圾集合处理),如果操作成功,则返回true,否则为false否则。因此,"删除"在 ninja 上不起作用,因此,简单地说,我对 ninja > ninja >正常工作。

因此,您可以忘记我所说的关于"参考"one_answers"删除"的所有内容,它们与它们无关,也不是真的。

最新更新