34005

[code]

    function func1 () {
    
      return Array(3).fill({}).map((item, index) => {
    
        return Object.assign(item, {index: index});
      });
    };
    
[/code]

私はこのfunctionの返り値が以下のようになるのを期待していました。

[code]

    console.log( func1() ); // [ { index: 0 }, { index: 1 }, { index: 2 } ]
    
[/code]

しかし実際は以下のような結果になりました。

[code]

    console.log( func1() ); // [ { index: 2 }, { index: 2 }, { index: 2 } ]
    
[/code]

これはObject.assign()の評価のタイミングの問題なのでしょうか？  
このことについて詳しく説明できる方がいれば教えていただきたいです。

ちなみに以下のようにObject.assignの評価を強制的にmap内で済ませることで期待する結果を返すことはできました。

[code]

    function func2 () {
    
      return Array(3).fill({}).map((item, index) => {
    
        return JSON.parse(JSON.stringify(Object.assign(item, {index: index})));
      });
    }
    
    console.log( func2() ) // [ { index: 0 }, { index: 1 }, { index: 2 } ]
    
[/code]


CC BY-SA 3.0
2017-04-14T06:45:32.310
34004
2017-04-14T08:54:54.627
14401
question
javascript
Object.assign()の評価タイミング（？）について


[Array.prototype.fill()](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill)の実装は単純な代入ですので、参照型の値を渡した場合、同じオブジェクトを各要素が参照することになります。

[code]

    const fillObj = {};
    const arr = Array(3).fill(fillObj);
    /* is equal to...
    for (let i = 0; i < 3; i++) {
        arr[i] = fillObj; // NOT arr[i] = {};
    }*/
    
    console.assert(arr.every(el => el === fillObj));
    
[/code]

これを回避する方法としては、[Spread syntax](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Operators/Spread_operator)と[Array.prototype.map()](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)を使用した方法があります。要素数を指定した配列初期化処理としても有用です。

[code]

    const arr = [...Array(3)].map((v, i) => ({ index: i }));
    
    console.assert(arr.every((el, i) => el.index === i));
    
[/code]


CC BY-SA 3.0
2017-04-14T07:03:20.217
34005
2017-04-14T08:54:54.627
2017-04-14T08:54:54.627
34004
answer