今天我偶然发现了Stack Overflow上的一个问题 - How do I remove objects from a javascript associative array?。令我印象深刻的是,接受的答案既误导又大幅上调,所以我强调了可能的陷阱。
然而,在纠正错误答案的同时,我意识到我不知道为什么让delete
保持元素 assign {{ 1}}而不是删除。
undefined
背后有理由吗?
答案 0 :(得分:11)
我意识到我不知道为什么
delete
分配未定义而不是删除是有意义的。
没有。 delete
从对象中删除属性,不将其设置为undefined
。这是一个简单的方法:
var a = ['a', 'b', 'c'];
console.log(1 in a); // logs "true"
delete a[1];
console.log(1 in a); // logs "false"
请注意,在delete
之后,a
不再具有名为1
的属性。完全没有。
对比:
var a = ['a', 'b', 'c'];
console.log(1 in a); // logs "true"
a[1] = undefined;
console.log(1 in a); // logs "true"
在那里,a
仍有一个名为1
的属性,只是该属性的值为undefined.
在JavaScript中了解arrays aren't really arrays at all非常有用。它们只是对象,数组“索引”只是属性名称(它们是字符串 - 是的,实际上,我们只是将它们写成数字),数组具有特殊的属性名称处理,这些属性都是数字(索引),特殊的length
属性,以及从Array.prototype
获得的一些函数。这在规范的Section 15.4中非常明确。一旦你坚定地认为JavaScript数组不是真正的数组,它们就更有意义了。 : - )
从数组中删除数组“index”属性不会更改其length
(即使删除编号最大的数据也不会更改);它只是在数组中创建了一个洞(JavaScript“数组”本质上是稀疏数组;例如,它们可能有间隙)。所以在我上面的第一个例子中,如果我这样做的话,我会得到完全相同的数组:
var a = [];
a[0] = 'a';
a[2] = 'c';
注意间隙,数组没有1
元素/属性。
如果你说:
var foo = a[3];
... foo
可以获得值undefined
,原因完全不同:
a
有一个名为3
的属性,其值为undefined
,或者:a
根本没有名为3
的属性;对于没有该名称属性的对象的属性访问器操作的结果是undefined
。这个if-no-property-return - undefined
以相当复杂的方式涵盖在规范中,但主要在Section 8.12.3中。这些是截然不同的事情。
答案 1 :(得分:6)
它不会指定undefined
。它删除了该属性。 (如果您尝试访问不存在的属性,您将获得undefined
,length
基于数组中编号最大的项目。)
这是有道理的,因为它可以在任何类型的对象上运行。为了使其起作用,如果它们是instanceof Array
,则必须使用特殊情况对象,但前提是它是具有数字名称的属性。
如果要从数组中删除项目,请使用splice
。
> var elements = [NaN, NaN, NaN];
> elements.splice(1,1);
> console.log(elements);
[ NaN, NaN ]
答案 2 :(得分:3)
JavaScript数组可以“稀疏”。也就是说,在从未分配值或删除值的意义上,某些槽可以是空的。如果您测试与该索引关联的值,则会返回undefined
,因为它不存在,而不是因为它被赋值undefined
。
当delete
从数组中删除项目时,它不会自动向上滑动其余元素以填充空间:其他元素保留其现有索引,这反过来意味着.length
属性不会更改,因为.length
被定义为等于最高分配的索引加一。
如果要删除数组元素并重新编号其他元素,请使用.splice()
method。
答案 3 :(得分:1)
这是因为delete
运算符删除了属性,而删除的属性具有值undefined
。要从数组中删除元素,可以使用splice
数组方法。
所有这一切都是因为javascript中的delete运算符如何工作。
当你没有设置对象的属性并尝试检查它的值时,它将是未定义的:
var obj = {};
alert(obj.foo); // undefined
与:
相同alert(obj['foo']); // undefined
看看这个:
// create empty object
var obj = {};
// check its property named 1
alert(obj[1]); // undefined
// set property named 1 to value 'fooo'
obj[1] = 'fooo';
// and check it
alert(obj[1]); // 'fooo'
// now delete it
delete obj[1];
// and check again
alert(obj[1]); // undefined
delete
删除了属性,其值为undefined
- 以上所有代码都是关于对象的。
现在看看数组:
var arr = []; // it's better to use [] than new Array();
alert(arr[1]); // undefined - same as above
// assign value
arr[1] = 'fooo'
// check it
alert(arr[1]); // 'fooo' - same as above
// remove it
delete arr[0];
// and check
alert(arr[1]); // undefined - same as above
所以行为是一样的,但是数组的length
属性呢?规范http://es5.github.com/#x15.4.5.2说:
“此Array对象的length属性是一个数据属性,其值始终在数字上大于名称为数组索引的每个可删除属性的名称。”
所以当你看到这个:
var arr = ['foo', 'bar', 'foobar'];
alert(arr.length); // 3
// delete first
delete arr[1];
// and check length
alert(arr.length); // 3
最后一次检查给出3,因为此数组中的最后一个deletable属性具有索引2 - 第一个属性(索引为0)具有值undefined
(删除运算符设置此值),第二个项目(具有索引1)具有值'bar'和第三个(索引2)的值为'foobar'。所以根据规格长度= 2 + 1('总体上数字大于最后删除');
这在以下代码中也可见:
var arr = [];
arr[10] = 'foo';
// element with index 10 is set to 'foo' but elements from 0 to 9 don't have value - they are undefined
// now check length
alert(arr.lenght); // 11
最后一个可删除属性索引是10,所以10 + 1给出11,尽管以前的元素是未定义的。