【问题标题】:Javascript array length modification implicationsJavascript 数组长度修改的含义
【发布时间】:2017-09-28 11:16:07
【问题描述】:

我在尝试扩展 Array.prototype 时注意到了一些事情。我本质上是想写一个允许删除数组中最后一项的方法:

Array.prototype.removeLast = function() {
    delete this[this.length - 1];
};

这不会产生我预期的结果:

>>> var arr = [ 1, 2, 3 ];
[ 1, 2, 3 ]
>>> arr.removeLast();
undefined
>>> arr
[ 1, 2, undefined ]

所以我尝试了另一种方法:

Array.prototype.removeLast = function() {
    this.length--;
};

我得到了预期的结果。

>>> var arr = [ 1, 2, 3 ];
[ 1, 2, 3 ]
>>> arr.removeLast();
undefined
>>> arr
[ 1, 2 ]

问题

1) 为什么数组索引删除不像对象键删除那样操作? (对于数组,引用似乎仍然存在,但只是引用了undefined。对于对象,引用似乎被完全删除了。)

2) this.length-- 方法安全吗?是否会导致内存泄漏,或者确实 更改对象的 length 属性也会导致运行检查并删除数组中任何被遗忘的索引?

3) 前两个问题的答案是否因实施而异?

4) removeLast 的好的实现是什么?

谢谢!

【问题讨论】:

  • 首先你不应该改变 Array 原型。其次,delete 删除给定索引上的对象,但不更改数组的长度。第三,它有原生的更好的函数,比如pop()splice(),它们会改变数组的结构。
  • 3) 和 4) 在 1) 和 2) 中回答
  • 虽然是一个很好的参考(从 2012 年开始),但重要的是要注意 (1) 引用了旧的 ECMA 标准,此外,虽然标准有助于定义期望,但它通常不会定义某些东西是如何实现的(浏览器当标准不具体时表现不同),或者在将某个功能纳入标准之前包含该功能。

标签: javascript arrays


【解决方案1】:

正如 MDN 为 deleting array elements 解释的那样:

删除数组元素时,数组长度不受影响。即使您删除了数组的最后一个元素,这仍然成立。

当删除操作符删除一个数组元素时,该元素不再在数组中。在以下示例中,trees[3] 使用 delete 删除。

对于您的数组,您正在尝试删除一个索引(使用它,它的值),这是使用delete 运算符执行的,但不是您想的那样。索引/值已被删除,但 JavaScript 引擎如何组装数组并操作其属性(例如,length)不会按照您的想法进行。它仍然会显示带有undefined 的缺失索引,这就是您所看到的。

演示

为了更好地演示,如果Object.keys( your_array ) 你会看到你删除的数组的索引不存在;同样,如果您执行Object.values( your_array ),您将看到undefined 没有返回。出于所有意图和目的,您删除了该属性(索引)及其关联值。

其他注意事项

您可以考虑使用splicepop(如果是最后一个索引)来删除数组的最后一个元素;然而,这并非没有认识到它们自身的影响:

  • splice 将重新排列数组,将值转移到新的索引中;这与 delete 不同,后者将所有内容都保留在其原始索引中

  • pop 将只删除数组中的最后一项/索引

  • splicepop 都将更新数组的 length 属性

deletesplicepop 的示例

console.log('\nDELETE');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val)); // notice no undefined


console.log('\nPOP');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.pop();
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val));


console.log('\nSPLICE');
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log('array: ', trees);
console.log('keys: ', Object.keys(trees) );
console.log('values: ', Object.values(trees) );
console.log('length: ', trees.length );
trees.forEach(val=>console.log(val));

问题

1) 为什么数组索引删除不像对象键删除那样操作? (对于数组,引用似乎仍然存在,但只是引用未定义。对于对象,引用似乎被完全删除。)

是的。

2) this.length-- 方法安全吗?它会导致内存泄漏,还是改变对象的长度属性也会导致检查运行并删除数组中任何被遗忘的索引?

最好不要自己操作和管理长度。从历史上看,不同的浏览器对 length 操作的反应不同。

近年来,我唯一一次看到length 使用的操作是清除数组(即arr.length = 0)。当数组可能包含某些不应丢失或重建的属性时,这比将其分配给新的空数组(即arr = [])更可取。

3) 前两个问题的答案是否因实施而异?

是的

4) removeLast 的好的实现是什么?

arr.pop()arr.splice(-1,1)

【讨论】:

  • 不能使用delete 运算符来执行。证明它!
  • @ibrahimmahrir 我实际上正在编辑这个答案,请稍等
  • 我忘记了pop,看来您已经找到了我正在寻找的 MDN 部分!但我也很好奇[].length 修改可能导致内存泄漏。 this.length-- 是不安全的操作吗?
  • “无法删除不可配置的属性。这包括内置对象的属性,如 Math、Array(...)” - 但他不想删除不可配置的属性,既不是 Array 对象也不是索引。
  • @Kinduser 是的,你是对的,我正在编辑过程中,因为我将此与另一个问题混淆了,我正在回答并复制/粘贴错误的 sn-p — 我认为它已更新跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2012-05-20
相关资源
最近更新 更多