【问题标题】:Strange behavior of an array filled by Array.prototype.fill()由 Array.prototype.fill() 填充的数组的奇怪行为
【发布时间】:2016-12-13 13:09:43
【问题描述】:

我遇到了一些我对数组不理解的问题。事实上,我创建了一个数组,我用空子数组填充了一个 2D 矩阵。 但是当我操作数组时,它的行为并不像我预期的那样。

var arr = new Array(5);
arr.fill([]);
arr[2].push("third rank item");
console.log(arr);

//[ [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ] ]

这件事上的每一个亮点都会受到欢迎

【问题讨论】:

  • 你期望它的表现如何?
  • 您正在填充 same 空数组。你可以试试Array.from(new Array(5), () => [])
  • @torazaburo 你能简单解释一下吗? OP 针对外部数组中的第 3 项并推送了一个字符串,该字符串导致将字符串推送到所有内部数组中。有点混乱。
  • 所有内部数组都是同一个数组。
  • 所有内部数组都是同一个数组。

标签: javascript arrays


【解决方案1】:

这是同样的老问题,数组(和一般的对象)是引用而不是值。

具体来说,当您执行arr.fill([]) 时,您将使用一个空数组并使用它来填充父数组。

这就像说:

var arr = new Array(5);
arr[0] = arr[1] = arr[2] = arr[3] = arr[4] = [];

它们都指向同一个数组!所以当你继续修改其中一个时,看起来它们都被修改了(但实际上它仍然是同一个)

不幸的是,没有简单的方法可以为每个数组分配一个空数组。你可以这样做:

Array.apply(null, Array(5)).map(function() {return [];});

基本上,创建一个长度为 5 的(已初始化)空数组,并将每个(空)值映射到一个新的 []

编辑:好像我被困在了旧时代。根据@torazaburo 的评论,您可以使用Array.from 而不是Array.apply(null, Array(5)).map,如下所示:

Array.from( new Array(5), function() { return []; } );

【讨论】:

    【解决方案2】:

    您可以注意到使用 array.fill 您正在使用对同一数组的引用填充数组,

    如果您想将每个数组索引实例化为一个空数组,则可以使用普通的 while 循环:

    var arr = [];
    var n = 5
    while(n--)
      arr[n] = []
    
    arr[2].push("third rank item");
    console.log(arr);

    选项 2:
    如果您有可用的 lodash 包,您也可以使用 _.map,因为它专门设计用于循环遍历稀疏数组(本机地图将跳过非初始化值)

    var arr =_.map(new Array(5), (x => []))
    
    arr[2].push("third rank item");
    console.log(arr)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

    【讨论】:

      【解决方案3】:

      Array.prototype.fill 的ECMA doc 的第 11 行显然给出了神秘的原因。

      重复,而 k

      令 Pk 为 ToString(k)。

      设 setStatus 为 Set(O, Pk, value, true)。

      ReturnIfAbrupt(setStatus).

      将 k 增加 1。

      这里的“价值”只是收到的参考。他们将其设置为直接数组的属性。这意味着所有填充的数组都只是对单个数组对象的引用。

      【讨论】:

        【解决方案4】:

        这是发生参考的原因。数组是一种对象,当您使用 [] or new Array() 填充数组并将相同的数组放入所有索引中时,对象会处理它们的引用,这就是为什么当您更新子数组时所有索引都会更新。

        解决方案:

        let arr = new Array(5).fill(0).map(ele => ele = []); arr[2].push("something");

        let arr = Array.of([], [], [], []); arr[2].push("something");

        结果:正如预期的那样,arr 仅更新了 2 个索引。

        【讨论】:

          【解决方案5】:

          对于 ES6,我推荐这种方法来创建 2 维或多维数组:

          // create an M x N dimension grid and fill it with 0's
          const myArray = [...Array(M)].map(r => [...Array(N)].map(r => 0));
          

          【讨论】:

            【解决方案6】:

            试试这个,这是一条为您提供快速解决方案。

            var arr = new Array(5);
            arr = Array.from(arr, x => []);
            arr[2].push("third rank item");
            console.log(arr);

            【讨论】:

              【解决方案7】:

              你可以试试这个,

              var arr = new Array(5);
              var i = 0;
              while (i < arr.length)
                arr.fill([], i++);
              arr[2].push("third rank item");
              console.log(arr);

              【讨论】:

                【解决方案8】:

                有点不同:

                let array= JSON.parse(JSON.stringify(new Array(N).fill([])));
                

                let array=new Array(N).fill(null).map(()=>[]);
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-12-30
                  • 2017-08-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-03-20
                  相关资源
                  最近更新 更多