为什么Array.prototype.push返回新的长度而不是更有用的东西?

时间:2015-12-14 03:00:20

标签: javascript specifications return-type

ECMA-262, 3rd Edition引入以来,Array.prototype.push方法的返回值为Number

  

15.4.4.7 Array.prototype.push([item1 [,item2 [,...]]])

     

参数将按照它们出现的顺序附加到数组的末尾。 作为调用的结果,返回数组的新长度

返回数组的新长度背后的设计决策是什么,而不是返回可能更有用的东西,例如:

  • 对新添加的项目/ s的引用
  • 变异数组本身

为什么这样做,是否有关于如何做出这些决定的历史记录?

4 个答案:

答案 0 :(得分:3)

posted this in TC39's communication hub,并且能够进一步了解其背后的历史:

  

pushpopshiftunshift最初是在1997年添加到JS1.2(Netscape 4)中的。

     

以Perl中类似命名的函数为模型。

     

JS1.2 push遵循Perl 4约定,返回最后一个被推送的项目。   在JS1.3(1998年夏季的Netscape 4.06)中,更改了推送以遵循Perl 5约定,即返回数组的新长度。

     

请参阅https://dxr.mozilla.org/classic/source/js/src/jsarray.c#804

/*
 * If JS1.2, follow Perl4 by returning the last thing pushed.  Otherwise,
 * return the new array length.
 */

答案 1 :(得分:2)

我无法解释为什么他们选择返回新的长度,但是回应你的建议:

  • 返回新添加的项目:

鉴于JavaScript使用C样式赋值来发出指定值(而不是基本样式赋值),你仍然可以有这种行为:

var addedItem;
myArray.push( addedItem = someExpression() );

(虽然我知道这确实意味着你不能将它作为声明+赋值组合中r值的一部分)

  • 返回变异数组本身:

这将是“流畅的”API的风格,在ECMAScript 3完成后显着获得了普及,并且它不会保持ECMAScript中其他库功能的风格,并且再次,它不是那么多额外的工作通过创建自己的push方法来启用您所关注的方案:

Array.prototype.push2 = function(x) {
    this.push(x);
    return this;
};

myArray.push2( foo ).push2( bar ).push2( baz );

或:

Array.prototype.push3 = function(x) {
    this.push(x);
    return x;
};

var foo = myArray.push3( computeFoo() );

答案 2 :(得分:2)

因为你问我很好奇。我制作了一个示例数组并在Chrome中进行了检查。

var arr = [];
arr.push(1);
arr.push(2);
arr.push(3);
console.log(arr);

enter image description here

因为我已经引用了数组以及我推入的每个对象,所以只有一个其他属性可能有用......长度。通过返回Array数据结构的这一附加值,我现在可以访问所有相关信息。这似乎是最好的设计选择。如果您想为保存1台单机指令而争辩,那么或者根本不返回任何内容。

  

为什么这样做,是否有关于如何做出这些决定的历史记录?

毫无头绪 - 我不确定存在这些方面的理由记录。这将取决于实施者,并且很可能在任何给定的代码库中对实施ECMA脚本标准进行评论。

答案 3 :(得分:2)

我理解array.push()期望返回变异数组而不是新长度。并希望将这种语法用于链接原因 但是,有一种内置方法可以执行此操作:array.concat[]

newArray = oldArray.concat[newItem];

可以使用.concat[]代替.push()来完成数组链接。

以下是React中用于更改state变量的常用模式,基于其先前值:

// the property value we are changing
selectedBook.shelf = newShelf;

this.setState((prevState) => (
  {books: prevState.books
           .filter((book) => (book.id !== selectedBook.id))
           .concat(selectedBook)
  }
));

state对象具有books属性,其中包含book数组。
book是一个包含idshelf属性(以及其他)的对象 setState()接受一个对象,该对象包含要分配给state

的新值

selectedBook已在books数组中,但其属性shelf需要更改。
但是,我们只能给setState一个顶级对象 我们不能告诉它去寻找这本书,并在那本书上找一个属性,并给它这个新的价值。

所以我们按原样采用books数组 filter删除selectedBook的旧副本 然后concat在更新selectedBook属性后重新添加shelf

想要链接push的好用例 但是,正确的方法是使用concat

要点: array.push()将返回一个数字(变异数组的新长度) array.concat[]将返回变异数组。