Array.prototype.fill() 与对象传递引用而不是新实例

IT技术 javascript arrays
2021-01-22 07:19:16

我有点玩弄并试图实例化一个新的 length 数组x,其中该数组的所有元素都被初始化为一个值y

var arr = new Array(x).fill(y);

如果 of 的值y不是object ,这很有效这意味着如果y是一个对象,则以下为真:

var arr = new Array(2).fill({});
arr[0] === arr[1]; //is true;
arr[0].test = 'string';
arr[1].test === 'string'; //is also true;

有没有办法说明在使用填充函数时应该为每个元素创建一个新对象?还是我应该将其转换为循环?

6个回答

您可以首先fill使用任何值(例如undefined的数组,然后您将能够使用map

var arr = new Array(2).fill().map(u => ({}));
var arr = new Array(2).fill().map(Object);
不幸的是,这种方式的性能并不是最好的。我在下面的答案中添加了更多解释。
2021-03-11 07:19:16
@Slai 非常好的答案,谢谢。我花了一段时间才弄明白,但这是值得的。
2021-03-18 07:19:16
Array.from({length:2}, u => ({}))
2021-03-30 07:19:16

接受的答案很好,并且在 90% 的情况下都有效。

但是,如果您正在制作高性能 JS 应用程序,并且如果您使用大/巨大的数组,则Array.map(..)在内存和处理器使用方面造成很大的过载,因为它会创建数组的副本。

我建议使用经典的for循环:

    a = new Array(ARRAY_SIZE);
    for (var i = 0; i < ARRAY_SIZE; i++) {
        a[i] = [];
    }
    // or it's one line alternative
    for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);

我测试了六种替代方案并得到了这个:

  • Array.map(),如上所述(11 倍!慢):

     a = new Array(ARRAY_SIZE).fill().map(u => { return []; });
    
  • for 循环,最好的(最快的):

     // Standard multi-line way
     a = new Array(ARRAY_SIZE);
     for (var i = 0; i < ARRAY_SIZE; i++) {
         a[i] = [];
     }
    
     // One line syntax
     for (var i = 0, a = []; i < ARRAY_SIZE; a[i++] = []);
    
  • forEach6 倍):

     a = new Array(ARRAY_SIZE).fill();
     a.forEach((val, i) => {
         a[i] = [];
     })
    

[更新 2020-08-27] 下面 Ilias Karim 提出的另一种方法

  • Array.from30 倍!慢) - 尽管有最好的语法,但在性能方面显然更差 :(

     a = Array.from({ length: ARRAY_SIZE }, () => []);
    
  • [..Array(..)]5 倍!!!慢)

     a = [...Array(ARRAY_SIZE)].map(_=>([]))
    
  • Array.push(..),在性能方面排名第二(2x 倍!!!慢)

     let a = [], total = ARRAY_SIZE;
     while(total--) a.push([]);
    

附注。我用这个小提琴进行测试。

@user120242 我不明白你的评论?这个问题的意思是:如何用值初始化数组?我只是与接受的答案进行了比较,并发现了更快的方法。如果您对数组初始化有更好的建议,请填写与我们分享:)
2021-03-23 07:19:16
这既不公平也不有效,因为您预先初始化了数组并为 for 循环创建了一个 PACKED 数组。您的基准测试将重复的对象初始化时间与预初始化的本机数组迭代进行比较。去掉数组的预填充,或者将元素的类型更改为非同质的,这个基准就崩溃了。
2021-04-07 07:19:16

一种高性能解决方案: Array.from({ length: 5 }, () => new Object())

可以写得更短: Array.from({length:5}, _=>{})
2021-03-16 07:19:16
@morphles_=>({})如果你想初始化对象,它应该是否则,您只需用undefined.
2021-03-23 07:19:16
检查jsperf。从 v80 开始,微基准值承受、填充和映射仍然优于 Chrome 中的 array.from。很可能是因为 PACKED 数组迭代速度更快
2021-04-03 07:19:16
我刚刚在上面的答案中添加了这种初始化方式,显然,就性能而言,这是更糟糕的方式。在我的测试中,与常规for 循环相比,这种方式显示的结果30 倍
2021-04-04 07:19:16

最短可能:

let node =  [...Array(2)].map(_=>({}))
console.log(node)

我也测试了这个,它比旧式for 循环慢 5 倍请参阅我上面的性能测试答案。
2021-03-27 07:19:16

伊利亚斯·卡里姆 (Ilias Karim) 的回答非常出色。我只是做了以下事情:

a = Array.from({length:l}, () => new Array(c).fill(prefix));

创建一个指定大小的预填充二维数组,l by c,填充前缀。现在我的代码可以填充二维矩阵中需要非前缀值的插槽。