JavaScript中的对象删除

395

我对JavaScript的delete操作符感到有些困惑。看下面这段代码:

var obj = {
    helloText: "Hello World!"
};

var foo = obj;

delete obj;
执行完这段代码后,objnull,但是foo仍然引用着一个和obj完全一样的对象。我猜测这个对象就是foo指向的那个对象。
这让我感到困惑,因为我本来希望使用delete obj语句可以从内存中删除obj所指向的对象,而不仅仅是删除变量obj本身。
这是因为JavaScript的垃圾回收器是基于保留/释放机制工作的,所以如果没有其他变量指向这个对象的话,它将会被从内存中删除。
(顺便说一下,我的测试是在Safari 4上进行的。)

8
以下是翻译的结果:供您参考。 https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/delete_Operator - Daniel A. White
3
以上链接应更改为:http://perfectionkills.com/understanding-delete。 - johnmdonahue
1
@Steve Harrison,delete 在 JavaScript 中不是删除一个对象的操作,而是删除一个对象的键。在您的情况下,应该使用 remove 操作。var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;注意:对象并没有被删除,请检查 obj。 正确的用法是:delete obj.helloText 然后再检查 foo,此时 foo 就变成了一个空对象。 - Umair Ahmed
2
@UmairAhmed,自由翻译:delete`在Javascript中并不是用于删除对象的。`delete`用于移除对象的键。在您的情况下 `var obj = { helloText: "Hello World!" }; var foo = obj; delete obj;`, 对象并没有被删除。请检查`obj`。然后运行`delete obj.helloText`,您会看到`foo`现在指向一个空对象。 - Pacerier
可能会对您有所帮助:如果您正在使用Object.defineProperty()/Object.defineProperties()定义属性,任何未显式设置为configurable: true的属性都无法被删除。嘿,我曾经为此苦恼了一段时间。 - Phil Tune
14个回答

483

delete操作符仅删除引用,从不删除对象本身。如果它删除了对象本身,其他剩余的引用将会失效,就像C++中的delete一样。(访问它们之一将导致崩溃。使它们全部变为空值意味着在删除或每个对象上拥有额外的内存时需要进行额外的工作。)

由于Javascript是垃圾回收的,您不需要删除对象本身,它们将在没有任何方式可以引用它们时被删除。

如果您已经完成了对对象的引用,则删除对该对象的引用可能很有用,因为这为垃圾回收器提供了更多关于可回收内容的信息。如果仍然存在对大对象的引用,则即使程序的其余部分实际上并未使用该对象,也可能导致该对象无法回收。


30
delete 关键字仅适用于对象的属性,而不是变量。详见:http://perfectionkills.com/understanding-delete/ - Alex Mund
2
@AlexJM 是的,Guffa 的下一个回答(以及它的评论)详细讨论了这个问题。 - Jesse Rusak
1
一个对象的属性可以是另一个对象。例如:var obj = {a: {}}; delete obj.a; - Alex Mund
3
但是...变量实际上不就是window的属性吗? - user5147563
4
@Soaku 不是本地变量(例如那些使用var声明的变量)。 - Jesse Rusak
如何“删除对一个对象的引用”? - undefined

169
delete 命令对于普通变量没有影响,只有针对属性才起作用。在执行 delete 命令后,该属性不会具有 null 值,而是根本不存在。
如果该属性是对象引用,则 delete 命令会删除该属性但不会删除该对象。如果没有其他引用指向该对象,垃圾回收器会处理它。
示例:
var x = new Object();
x.y = 42;

alert(x.y); // shows '42'

delete x; // no effect
alert(x.y); // still shows '42'

delete x.y; // deletes the property
alert(x.y); // shows 'undefined'

(在 Firefox 中测试。)


40
如果在全局作用域执行此代码,你的 x 变量就成为了全局 window 对象上的一个属性,而 delete x; 确实会完全删除 x 变量。 - Crescent Fresh
18
只有在隐式声明的情况下它才是属性。如果像例子中那样明确声明,它就是全局变量,无法被删除。 - Guffa
4
@Tarynn: 我明白了,问题就出在这里。如果你在控制台中这样做,在某些浏览器中 x 将不会成为一个合适的变量,而是 window 对象中的一个属性。当然,这是控制台的问题,并不反映代码通常执行的方式。 - Guffa
2
@Guffa 在进行了大量研究后,我不得不承认没有足够的声望来进行反对投票可能是一件好事。我最真诚的道歉,并感谢您花时间向我展示发生了什么...这里是一个深入的解释: http://perfectionkills.com/understanding-delete/#firebug_confusion - Tarynn
2
@chao:我明白了。你遇到了和Tarynn一样的问题(请参见之前的评论)。当你在控制台中这样做时,它与实际代码中的效果不同。 - Guffa
显示剩余16条评论

58
"

隐式声明的变量

"是全局对象的属性,因此删除操作就像对任何属性一样。使用var声明的变量是不可摧毁的。"

66
我从未意识到var这么酷。 - Gavin
1
这是一个很好的观点,也是JS中的一个陷阱。人们习惯于删除window变量,然后想知道为什么不能对局部变量做同样的操作。 - welbornio
2
同样适用于 let - Pacerier

24

6

delete在JavaScript中不用于删除对象。

delete用于删除您的情况下的对象键

var obj = { helloText: "Hello World!" }; 
var foo = obj;
delete obj;

对象未被删除,请检查对象是否仍然保持相同的值 删除用法:

delete obj.helloText

然后检查 obj, foo,它们都是空对象。


2

2
将变量设置为null可以确保在所有浏览器中断开与DOM元素和Javascript作用域之间的循环引用。使用delete命令将标记对象以在下一次垃圾回收运行时清除,但如果有多个变量引用同一个对象,则删除单个变量不会释放该对象,它只会删除该变量与对象之间的链接。在下一次垃圾回收运行时,只有变量将被清除。

2

我在这个问题上发现了一个jsperf,与此相关的内容可能会让你感兴趣。(将其保存下来以完善这个问题可能会很方便)

它比较了delete、设置null和设置undefined

但请记住,它测试的是多次删除/设置属性的情况。


1

IE 5到8存在一个错误,即在主机对象(Window、Global、DOM等)的属性上使用delete会抛出TypeError“对象不支持此操作”。

var el=document.getElementById("anElementId");
el.foo = {bar:"baz"};
try{
    delete el.foo;
}catch(){
    //alert("Curses, drats and double double damn!");
    el.foo=undefined; // a work around
}

如果您需要检查属性是否具有有意义的值,请使用el.foo !== undefined,因为在IE中"foo" in el将始终返回true。

如果您真的需要使属性真正消失...

function hostProxy(host){
    if(host===null || host===undefined) return host;
    if(!"_hostProxy" in host){
       host._hostproxy={_host:host,prototype:host};
    }
    return host._hostproxy;
}
var el=hostProxy(document.getElementById("anElementId"));
el.foo = {bar:"baz"};

delete el.foo; // removing property if a non-host object

如果您需要使用主机 API 的主机对象...

el.parent.removeChild(el._host);

1
我在寻找同样的答案时偶然发现了这篇文章。我最终做的是弹出对象中存储的所有值/对象,以便重复使用该对象。不确定这是否是一种不好的做法。这种技术对我在Chrome开发工具或FireFox Web控制台中测试我的代码非常有用。

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