Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array.fill gives same object repeated. why? [duplicate]

var arr = new Array(4).fill({});

arr[2].status = true;

console.log(arr[0].status); 

why is array fill filling same object in all indexes?

like image 760
Shishir Arora Avatar asked Apr 08 '17 13:04

Shishir Arora


2 Answers

.fill will insert the same exact object (same instance) on each segment of the array.
That's why doing .fill(Math.random) will return an array filled with always the same number.

You can do this to obtain what you want:

new Array(4).fill().map(() => ({}));

To explain what's happening under the hood in your question's code, let's convert this to ES5 code:

var arr = new Array(4);  // new Array(4)
var obj = new Object();  // *1: with this object instance
for(i = 0; i < 4; i++) { // .fill( *1 )
  arr[i] = obj;
}

As you can see, we are assigning the same object instance (obj) to each cell of the array instance.

This is the same principle of why:

const obj = {};
const a = obj;
const b = obj;

a.foo = true;

Makes a.foo === b.foo resolve to true.

like image 97
Fez Vrasta Avatar answered Nov 06 '22 14:11

Fez Vrasta


fill repeats the value you pass it. The value in this case is an object reference. Every copy of that reference refers to the same object, so what you're getting is:

       +−−−−−−−−−+
arr−−−>| (array) |
       +−−−−−−−−−+         +−−−−−−−−−−−−−−+
       | 0       |−−+−+−+−>|   (object)   |
       | 1       |−/ / /   +−−−−−−−−−−−−−−+
       | 2       |−−/ /    | status: true |
       | 3       |−−−/     +−−−−−−−−−−−−−−+
       +−−−−−−−−−+       

If you want separate objects, you'll need to create multiple objects. The simplest way is, of course:

var arr = [{}, {}, {}, {}];

Example:

var arr = [{}, {}, {}, {}];
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

If you want to do it with a variable length:

Since you're using Array.fill, I'm assuming you're using ES2015 (aka "ES6") features (but see below for an ES5-compatible solution without polyfills). You can do that via Array.from with a callback:

const arr = Array.from({length:4}, () => ({})); 
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

That gives you:

                    
       +−−−−−−−−−+       
arr−−−>| (array) |       
       +−−−−−−−−−+         +−−−−−−−−−−−−−−+
       | 0       |−−−−−−−−>|   (object)   |
       | 1       |−−−−−+   +−−−−−−−−−−−−−−+
       | 2       |−−−+ |   
       | 3       |−+ | |   +−−−−−−−−−−−−−−+
       +−−−−−−−−−+ | | +−−>|   (object)   |
                   | |     +−−−−−−−−−−−−−−+
                   | |     
                   | |     +−−−−−−−−−−−−−−+
                   | +−−−−>|   (object)   |
                   |       +−−−−−−−−−−−−−−+
                   |       | status: true |
                   |       +−−−−−−−−−−−−−−+
                   |                      
                   |       +−−−−−−−−−−−−−−+
                   +−−−−−−>|   (object)   |
                            +−−−−−−−−−−−−−−+

(You can do that with an Array.from polyfill on ES5 if you like, just use function() { return {}; } instead of () => ({}).)


In ES5, if you need a variable length, the simplest thing is probably just a loop:

var arr = [];
for (var i = 0; i < 4; ++i) {
    arr[i] = {};
}
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

You could put that in a helper function, of course.

like image 30
T.J. Crowder Avatar answered Nov 06 '22 15:11

T.J. Crowder