删除斧头vs斧头=未定义


138

两者中的任何一个有实质性的区别吗?

delete a.x;

a.x = undefined;

哪里

a = {
    x: 'boo'
};

可以说它们相等吗?

(我没有考虑诸如“ V8喜欢不使用delete更好的东西”之类的东西)


2
delete运算符将完全删除属性。将属性设置为undefined将删除该值。将属性设置为null会将值更改为null值。如果您喜欢,这是一个性能测试:jsperf.com/delete-vs-undefined-vs-null/3
j08691 2013年

1
@ j08691 Nit:它不会删除该值。它分配undefined作为值,它仍然是一个值..

您应该谈谈为什么要关心这个问题,然后答案才能满足您的实际问题。
Juan Mendes

Answers:


181

它们不相等。主要区别在于设置

a.x = undefined

表示a.hasOwnProperty("x")仍将返回true,因此,它仍将for in循环显示,并在Object.keys()

delete a.x

表示a.hasOwnProperty("x")将返回false

它们相同的方式是您无法通过测试来判断属性是否存在

if (a.x === undefined)

如果要尝试确定属性是否存在,应该不执行该操作,应该始终使用

// If you want inherited properties
if ('x' in a)

// If you don't want inherited properties
if (a.hasOwnProperty('x'))

遵循原型链(由zzzzBov提到),调用delete将允许它向上扩展原型链,而将值设置为undefined将不会在链接的原型中寻找属性http://jsfiddle.net/NEEw4/1/

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
extended.x = "overriding";
console.log(extended.x); // overriding
extended.x  = undefined;
console.log(extended.x); // undefined
delete extended.x;
console.log(extended.x); // fromPrototype

删除继承的属性如果您要删除的属性是继承的,delete则不会影响它。也就是说,delete仅从对象本身删除属性,而不从继承的属性删除。

var obj = {x: "fromPrototype"};
var extended = Object.create(obj);
delete extended.x;
console.log(extended.x); // Still fromPrototype

因此,如果需要确保对象的值是不确定的,delete则在继承该属性时将不起作用,undefined在这种情况下,您必须将其设置(覆盖)为。除非正在检查的地方将使用hasOwnProperty,但是假设在所有检查它的地方都将使用将是不安全的hasOwnProperty


1
"x" in a也将true与前者和false后者一起返回。的输出Object.keys也将不同。
lonesomeday

为什么您声明我不应该检查未定义?对我来说似乎足够合理。
bevacqua

@Nico因为这不会告诉您属性是否存在。我并不是说永远不要使用它。但是,如果您要检查undefined,则最好只检查if (a.x),除非它是用于数字且0是有效的
Juan Mendes

33

解释这个问题:

delete a.xa.x = undefined等价的吗?

没有。

前者从变量中删除键,后者则将值设置为undefined。在遍历对象的属性以及使用时间时,这会有所不同hasOwnProperty

a = {
    x: true
};
a.x = undefined;
a.hasOwnProperty('x'); //true
delete a.x;
a.hasOwnProperty('x'); //false

此外,当涉及原型链时,这将产生重大变化。

function Foo() {
    this.x = 'instance';
}
Foo.prototype = {
    x: 'prototype'
};
a = new Foo();
console.log(a.x); //'instance'

a.x = undefined;
console.log(a.x); //undefined

delete a.x;
console.log(a.x); //'prototype'

2
+1关于delete允许其沿原型链上升的要点
Juan Mendes 2013年

4

如果a.x是setter函数,a.x = undefined则将调用该函数,而delete a.x不会调用该函数。


3

是,有一点不同。如果使用delete a.xx,则不再是a的属性,但是如果使用a.x=undefinedx是属性,但其值未定义。


2

名称有些混乱。a.x = undefined只是将属性设置为undefined,但该属性仍然存在:

> var a = {x: 3};
> a.x = undefined;
> a.constructor.keys(a)
["x"]

delete 实际上删除它:

> var a = {x: 3};
> delete a.x;
> a.constructor.keys(a)
[]

1

来自节点的此REPL应该说明差异。

> a={ x: 'foo' };
{ x: 'foo' }
> for (var i in a) { console.log(i); };
x
undefined
> a.x=undefined;
undefined
> for (var i in a) { console.log(i); };
x
undefined
> delete a.x;
true
> for (var i in a) { console.log(i); };
undefined

1

我敢肯定,你可以看到之间的差异var o1 = {p:undefined};var o2 = {};

在这两种情况下,o.pundefined但在第一种情况下,这是因为这是和在第二种情况下,因为没有价值

delete是可让您从o1(或为其p属性分配值的另一个对象)进行以下操作的运算符o2delete o1.p;

只需通过undefined为属性分配一个值(在此示例中为该值,但可以是其他值)即可完成反向操作o1.p = undefined;

所以,它们不是等效的。


delete o.p;

  • p从对象中删除该属性(如果有一个)

  • 否则不做任何事情

o.p = undefined;

  • p如果对象尚不存在,请向其添加属性,并将其值设置为undefined

  • 只需更改属性的值(如果对象已经拥有)


从性能的角度来看,这delete不好的,因为它会修改对象的结构(就像在构造函数中未初始化新属性一样,它就像添加新属性一样)。

而将值设置undefined为也会释放内容,但不强制修改结构。


1

对象只是树的表示,这意味着在内存中,根指向存储该对象的键的各种存储位置。并且该位置指向存储该键的实际值的另一个位置,或者存储子键的位置,或者存储数组值的位置。

当您使用delete从对象中删除任何键时,实际上它会删除该键与其父对象之间的链接,并且键的存储位置及其值将被释放以存储其他信息。

当您尝试通过将undefined设置为键值来删除任何键时,那么您只是在设置其值,而不是删除该键。这意味着密钥存储位置仍与它的父对象和未定义密钥的值链接。

使用undefined而不是delete关键字是一个坏习惯,因为它不会释放该键的内存位置。

即使键不存在,并且您将其设置为undefined,该键也将使用value创建undefined

例如

var a = {};
a.d = undefined;
console.log(a); // this will print { d: undefined }

删除不能与继承的属性一起使用,因为该属性不是该子对象的一部分。


1
请注意,较新的引擎希望您不要删除键,因为这样做时,引擎需要为其创建新的类并在引用“类”的任何位置进行更新。
Juan Mendes

@JuanMendes,请您提供任何参考。
Laxmikant Dange

3
请参见使用delete关键字会影响对象的v8优化吗?TL; DR as a general rule of thumb, using 'delete' makes thing slower.developers.google.com/v8/design To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes. In V8, an object changes its hidden class when a new property is added.,最后smashingmagazine.com/2012/11/...
胡安·门德斯

1

使用数组而不是对象,我可以展示删除所使用的堆内存少于未定义的堆内存。

例如,此代码不会完成:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

它产生此错误:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

因此,您可以看到undefined实际上占用了堆内存。

但是,如果您还delete使用ary项目(而不是仅将其设置为undefined),则代码将慢慢完成:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

这些是极端的例子,但它们指出了delete我从未见过有人提及的地方。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.