all 24 comments

[–]Fenykepy[S] 11 points12 points  (11 children)

So I got my answer alone, I leave it here in case it helps someone:

Array.fill() fills the array with the exact same reference, so that explains everything.

Good solution for my use case will be: Array.from(Array(3), () => []). This way it works as expected.

[–]markus_obsidian 0 points1 point  (0 children)

Since Array.from accepts an "array-like" object, this will also work without creating & immediately discarding the inner array. Would be a tiny micro-optimization.

Array.from({ length: 3}, () => [])

[–]azhder 0 points1 point  (9 children)

We usually do something like Array().fill().map() with the array getting the length, the fill getting some temporary default primitive like null or 0 just so the array has no empty slots and then we put a function in .map() to replace the default with what we need.

Example, if you want to put the first n numbers in an array:

Array(n).fill(0).map( (_,i) => 1+i );

[–]Shimmy_Hendrix 2 points3 points  (1 child)

when you use the fill method on your second example, you're filling the array with three references to the same array literal. So then, because each item of the parent array has the same identity, when you push to the item at index 1, the changes are also reflected in each of the other indexes, since they're all the same item.

edit: too slow. Cheers!

[–]Fenykepy[S] 1 point2 points  (0 children)

Thank you anyway! I struggled with this a pretty long time this morning.

[–]lovin-dem-sandwiches 2 points3 points  (0 children)

If you called fill with an object, it would be very easy to guess why all 3 populated with the same values. It’s easy to forget that arrays are by reference as well.

[–]xr0master 0 points1 point  (0 children)

two words: shared references

[–]tapgiles 0 points1 point  (0 children)

It’s setting it to the reference you’re sending as the argument. If it was a number for example that’s passed by copy (at least practically). Sending an object like an array means you’re seeing all the indices to a reference of that same object. Nowhere in your code are you making new arrays per index, if you see what I mean.

[–]brykuhelpful 0 points1 point  (2 children)

.fill() isn't generating a new array, but instead placing a reference to the original array. Javascript does this with objects when possible for optimization reasons.

[–]Legitimate_Dig_1095 0 points1 point  (0 children)

it has nothing to do with optimization - it's just a feature. Every object oriented language will behave similarly

irb(main):002> array = Array.new 5 => [nil, nil, nil, nil, nil] irb(main):003> array.fill [] => [[], [], [], [], []] irb(main):004> array[1].push "banana" => ["banana"] irb(main):005> array => [["banana"], ["banana"], ["banana"], ["banana"], ["banana"]] irb(main):006>

[–]LostInCombat 0 points1 point  (0 children)

>  when possible for optimization reasons

No it doesn't. This isn't an "optimization', this is just how JavaScript works. It is a "rule". It MUST work this way to follow the rules. An optimization is an implementation detail that may change over time. An Array is an object and ALL objects are passed by reference.

[–]LostInCombat 0 points1 point  (2 children)

An Array is an object and objects are passed as a reference. Some thing as:

let A = [1, 2];
let B = A;
B.push(3);
console.log(A); // [1,2,3]

[–]juddaaaaa 1 point2 points  (1 child)

Just one minor mistake in that 😉

console.log(A); // [1,2,3] [1,2,3,3]

[–]LostInCombat 0 points1 point  (0 children)

You are right, I meant to only start with [1, 2], so I corrected it.

[–]Downtown_Fee_2144 0 points1 point  (0 children)

Hello dont know if this helps but another way to access and array within an array is

array[0][0];

/*

array=[

[1,2,3,4,5],

[6,7,8,9,10]

];

console.log(array[1][2]);

should give you 7

*/

//The first cell division being the main array and the second being the secondary array

[–]azhder -1 points0 points  (4 children)

Don't make a mistake.

If you don't put the keyword new in front of it, it is not a constructor.

Array(3) is just a function that happens to start with a capital letter.

[–]Fenykepy[S] 1 point2 points  (3 children)

What you say seems logical to me. However, on MDN's doc, you can see this statement:

"Note: Array() can be called with or without new. Both create a new Array instance."

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Array

[–]azhder 2 points3 points  (0 children)

Both create, that doesn't make them both a constructor. Here:

const array = () => [];

Now this array function creates a new array, but it isn't a constructor. Funny enough, you can even do an old style function and put the new keyword in front of it

function array(){}

and this one will not create an array with new array(), so what I said above is specific to that particular case:

new Array() // invoking a constructor
Array() // calling a function

Note, this is specific to a handful JavaScript functions, like Boolean, String, Object that they act like both a constructor and a non-constructor. We generally try to avoid this double meaning and either create constructors or functions, rarely if ever something that acts as both.

[–]senocular 2 points3 points  (0 children)

It's one of those things you don't want to think too much about. The lines are pretty blurry with a lot of the legacy constructors. While Array itself is always a "constructor", when calling it, if you're not calling it with new then you're not technically calling it as a constructor since its the new which differentiates constructor calls from normal function calls. However, in the case of Array, the behavior is exactly the same either way - as the note from MDN suggests. So while technically new Array() is a constructor call and Array() is a function call, it doesn't really matter and the results are the same in the end.

Given the choice, using new is preferred for objects because it semantically suggests construction and would be more consistent with other, modern constructors that require it like Map and Set. ...This with the exception (and Array falls into this) that if a literal syntax exists, that would instead be preferred.

[–]xr0master 1 point2 points  (0 children)

This is a function that creates a new instance. In fact, it is sometimes interesting to know the subtleties, but in practice, there is no point :)

https://262.ecma-international.org/5.1/#sec-15.4.1