向数组追加元素:直接赋值和使用“push”方法的区别?

5
arr.push(Math.random());

and

arr[arr.length]=Math.random();

拥有相同的结果。

那么,它们之间有什么区别呢?换句话说,什么时候使用前者比后者更好?


1
arr.push()是更常见的习惯用语,也更短。 - Barmar
请查看此链接以了解性能 https://jsperf.com/array-direct-assignment-vs-push 还有一个问题,其中包含很好的细节 https://dev59.com/rHRB5IYBdhLWcg3weHHx 。 - esertbas
1
@esertbas:那个测试基本上是有缺陷的(第三个测试用例是无意义的):array 在测试迭代之间被重复使用,因此 push 比赋值做了更多的工作。这里有一个真正比较相似并确保死代码优化不会启动的测试:https://jsperf.com/simple-array-append-comparison - T.J. Crowder
2个回答

7

它们之间有什么区别?

看着这个规范并思考一下,至少有六个区别:

  1. push(...) 是一个方法调用,而另一个是一个赋值操作。
  2. 你可以使用 push 添加多个元素:arr.push(one, two, three)。要使用赋值完成这个操作,需要多次赋值。(push 直到所有操作完成后才更新 length,而多次赋值会为每次赋值更新它。)
  3. push 检查数组的长度是否会变成 > 253-1,如果是,则抛出一个 TypeError;而赋值则不会,它只是愉快地创建了一个名称不是数组索引的属性。(这是一个有趣的检查,因为数组索引只允许最大为 232-1。但是规范在很多关于数组长度的地方都做了这个检查。)
  4. 由于 arr.push(...)arr 上查找 push,因此它可以被拦截(通过将新的 push 赋值给 arrArray.prototype)。赋值只能以每个属性为基础进行拦截(使用 setter 来设置 "0""1" 等),或通过 Proxy 进行拦截。
  5. 如果你正在使用具有 set 陷阱的数组的代理,而不是直接使用数组,你可能会观察到不同的 set 调用(因为 set 陷阱可能会直接在底层数组上设置值,因此你看不到针对 lengthset)。
  6. 正如 Redu 指出的那样arr.push(value) 的结果是数组的新长度;而 arr[arr.lenght] = value 的结果是被推入的值。
换句话说,何时使用前者而不是后者更好?完全取决于您。由于push是最终执行与赋值相同操作的方法调用(具有一些额外开销,例如length检查),因此在某些引擎或至少某些情况下,理论上可能比直接赋值略微慢一点; 但是,您的直接赋值需要查找arr.length。实际上,在现代引擎上,我看不到任何显着差异; test here,而且任何差异在现实世界中也极不可能有影响。除此之外和#2-#6,这只是样式选择。第5个示例(仅适用于支持ES2015 Proxy的JavaScript引擎):

const a = [];
const p = new Proxy(a, {
  set(target, prop, value) {
    console.log("Proxy set called for " + prop + " = " + value);
    target[prop] = value;
    return true;
  }
});
p[0] = "a";         // We don't see length set here
console.log(p[0]);
p.push("b");        // We do here, because `push` sets `length` through
                    // the proxy reference
console.log(p[1]);


2
除了T.J. Crowder在详细回答中提到的,实际应用中我使用其中之一还取决于一个因素。这就是我推送一个项目到数组时期望的返回值。
  • arr.push(item) 返回数组的新长度。
  • arr[arr.length] = item 返回已推送的项目。
  • arr.concat(item) 返回带有推送项目的新数组。
  • (arr.push(item),arr) 返回包含新推送项目的数组。
在函数式编程中,它们都有各自的用例。然而,特别是后两者,如果您不小心使用,可能会为您的代码引入巨大的差异和意外的错误,因为在JS中,数组是引用类型。
哦,顺便说一下,早期的书籍中提到的第一和第二个对性能没有任何影响,即使在微观性能方面也看不出任何差异。它们都非常快。

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