【问题标题】:Array.push return pushed value?Array.push 返回推送值?
【发布时间】:2014-04-29 03:25:28
【问题描述】:

修改Array.push() 以返回推送的对象而不是新数组的长度可能是一个坏主意,是否有任何实质性的原因?

我不知道这是否已经被提议或询问过;谷歌搜索只返回了无数与Array.push() 的当前功能相关的问题。

这是此功能的示例实现,请随时更正:

;(function() {
    var _push = Array.prototype.push;
    Array.prototype.push = function() {
        return this[_push.apply(this, arguments) - 1];
    }
}());

然后你就可以做这样的事情了:

var someArray = [],
    value = "hello world";

function someFunction(value, obj) {
    obj["someKey"] = value;
}

someFunction(value, someArray.push({}));

例如someFunction修改作为第二个参数传入的对象。现在someArray的内容是[{"someKey": "hello world"}]。

这种方法有什么缺点吗?

【问题讨论】:

  • 首先,改变内置对象的行为是个坏主意,因为它会破坏现有代码。其次,您将更改Array.prototype.push,而不是Array.push。此外,如果您需要使用 array[array.length - 1] 获取刚刚推送到数组中的元素,或者您可以在使用 .push() 之前将其存储在中间局部变量中,则始终可以获取它。坏主意。
  • 仅供参考,您还破坏了.push() 可以接受多个参数的语义。
  • 感谢您的收获。是的,我知道我可以获得最新的对象;事实上,我可以用一个班轮做到这一点:array[array.push(val) - 1]。我想这个“想法”是不必要的,但如果没有外部视角,我真的不明白为什么。我想,橡胶闪避之类的。哦,还有固定的语义。
  • 另外,如果您想发表您的评论作为答案,我会接受,因为您在 Bergi 之前做出了回应。否则,我会接受他的回答。
  • @RobG - 如果前面的语句没有正确地以分号结尾,那么作为 IIFE 的内容可能看起来像是调用函数的开始并导致意外错误甚至更糟糕的是,错误的执行。这实际上发生在我处理别人的代码时,他们的键盘上似乎有一个坏掉的分号键。

标签: javascript arrays


【解决方案1】:

See my detailed answer here

TLDR;
当您改为使用array.concat[] 添加元素时,您可以获得变异数组的返回值。

concat 是一种将两个数组“添加”或“连接”在一起的方式。这个方法很棒的地方在于它有一个结果数组的返回值,所以它可以被链接起来。

newArray = oldArray.concat[newItem];

这也允许您将函数链接在一起

updatedArray = oldArray.filter((item) => { item.id !== updatedItem.id).concat[updatedItem]};

在哪里item = {id: someID, value: someUpdatedValue}

主要需要注意的是,您需要将一个数组传递给concat。
因此,请确保将要“推送”的值放在几个方括号内,这样就可以了。
这将为您提供 push() 所期望的功能

您可以使用+ 运算符将两个数组“添加”在一起,或者将要连接的数组作为参数传递给concat()。

let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);

请注意,通过使用concat 方法,您可以利用concat 之前和之后的“链接”命令。

【讨论】:

  • 我来寻找为什么我不能链接Array.prototype.push() 的答案,这是迄今为止(几乎)最好的答案。最好的答案是targetArray.concat([newValue]).thenChainMoreStuff...
  • 这是一个很好的答案,但为什么它说你可以使用 + 添加数组,AFAIK 这不是真的
【解决方案2】:

修改Array.push() 以返回推送的对象而不是新数组的长度可能是一个坏主意,是否有任何实质性的原因?

当然有一个:其他代码将期望Array::push 的行为符合规范中的定义,即返回新的长度。如果您确实重新定义了内置函数以使其行为异常,其他开发人员会发现您的代码难以理解。

至少为方法选择一个不同的名称。

然后您可以执行以下操作:someFunction(value, someArray.push({}));

呃,什么?是的,我的第二点已经发生了:-)

但是,即使您没有使用push,这也无法表达您想要做的事情。您应该表达的组合是“将由键和值组成的对象添加到数组中”。更函数化的风格,让someFunction返回这个对象,就可以写了

var someArray = [],
    value = "hello world";

function someFunction(value, obj) {
    obj["someKey"] = value;
    return obj;
}

someArray.push(someFunction(value, {}));

【讨论】:

  • 我已经想到了。其他内部代码是否依赖返回值是新数组的长度?
  • @ElliotBonneville 你可以放心地假设很多东西都假设和使用它。
  • @ElliotBonneville:“内部代码”是什么意思?不,没有内置功能依赖于Array.prototype.push 的值。即使有任何东西使用了它,因为 ES5.1 这样的东西被指定直接引用内置的 _push 函数,而不是引用覆盖的属性。
  • 啊,好的。感谢您的洞察力。 +1
  • @ElliotBonneville——不符合 ECMA-262。我非常怀疑内置对象的内部方法无论如何都会使用公共接口,它们的行为纯粹用内部方法来表达([[Get]],[[Put]],[[Delete]] 等)。
【解决方案3】:

正如一个历史记录——有一个旧版本的 JavaScript——JavaScript version 1.2——它处理许多数组函数的方式完全不同。

特别针对这个问题,Array.push确实返回了item,不是数组的长度。

也就是说,1.2 几十年来都没有被使用过——但一些非常古老的参考资料可能仍然提到这种行为。

http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm

【讨论】:

  • 是否有任何理由说明为什么要更改? +1
  • @ElliotBonneville -- 我从来没有听说过,但我有点顺势而为,顺其自然。 1.2 在我进入事情的时候正在离开。
【解决方案4】:

ES6的到来,建议以适当的方式扩展数组类,然后,覆盖push方法:

class XArray extends Array {
   
   push() {
     super.push(...arguments);
     return (arguments.length === 1) ? arguments[0] : arguments;
   }
 
}
//---- Application
let list  = [1, 3, 7,5];

list = new XArray(...list);

console.log(
  'Push one item : ',list.push(4)
);

console.log(
  'Push multi-items :', list.push(-9, 2)
);

console.log(
   'Check length :' , list.length
)

【讨论】:

    【解决方案5】:
    var arr = [];
    var element = Math.random();
    assert(element === arr[arr.push(element)-1]);
    

    【讨论】:

      【解决方案6】:

      push() 方法返回最后添加的元素,这使得在创建短函数/reducer 时非常不方便。此外,push() - 在 JS 中是一个相当古老的东西。另一方面,我们有 spread operator [...] 其中 is faster 可以满足您的需求:它完全返回一个数组。

      // to concat arrays
      const a = [1,2,3];
      const b = [...a, 4, 5];
      console.log(b) // [1, 2, 3, 4, 5];
      
      // to concat and get a length
      const arrA = [1,2,3,4,5];
      const arrB = [6,7,8];
      console.log([0, ...arrA, ...arrB, 9].length); // 10
      
      // to reduce
      const arr = ["red", "green", "blue"];
      const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
      console.log(liArr);
        //[ "<li style='color:red'>red</li>", 
        //"<li style='color:green'>green</li>", 
        //"<li style='color:blue'>blue</li>" ]
      

      【讨论】:

      • 你能详细说明一下 push 是过时的吗?还是仅仅因为该功能已过时? (只是为了好奇)。顺便说一句,我正在寻找一个更优雅的解决方案,因为 push 在减速器上不方便,所以谢谢!
      • @EmilioGrisolía 今天,在 99% 的情况下,我们不需要改变对象,这就是为什么现在 push 它很少使用了。
      • 也就是说,如果你不关心效率的话。
      【解决方案7】:

      用 someArray[someArray.length]={} 代替 someArray.push({}) 怎么样?赋值的值就是被赋值的值。

      var someArray = [],
          value = "hello world";
      
      function someFunction(value, obj) {
          obj["someKey"] = value;
      }
      
      someFunction(value, someArray[someArray.length]={});
      
      console.log(someArray)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-02
        • 2016-12-27
        • 1970-01-01
        • 2012-06-27
        相关资源
        最近更新 更多