JavaScript - Why Array.Prototype.Fill Actually Fills a "Pointer" of Object When Filling Anything Like 'New Object()'

JavaScript - why Array.prototype.fill actually fills a pointer of object when filling anything like 'new Object()'

I am wondering why it's happening?

Array#fill takes the value you give it as the first argument, and fills the array with copies of that value.

The value you're giving it is a reference to an array, so naturally what it gives you back is an array filled with copies of that reference. Not copies of the array, copies of the reference.

E.g., it behaves this way for exactly the same reason this code:

var a = new Array(10);
var b = a;

...leaves us with a and b both referring to the same array (both containing the same value; a reference to the single array we've created).

Let's throw some Unicode-art at it:

After this code runs:

var a = new Array(10);
var b = a;

we have this in memory (minus a few irrelevant details):


a:Ref89895−−−+
|
| +−−−−−−−−−−−−−−−+
+−−−−−>| array |
| +−−−−−−−−−−−−−−−+
| | length: 10 |
b:Ref89895−−−+ +−−−−−−−−−−−−−−−+

a and b contain a reference, which I've shown here as Ref89895 although we never see the actual value. That's what's copied by b = a, not the array itself.

Similarly, when you do:

var matrix = new Array(10).fill(new Array(10), 0);

you end up with


+−−−−−−−−−−−−−−−+
matrix:Ref89895−−−>| array |
+−−−−−−−−−−−−−−−+
| length: 10 |
| 0: Ref55462 |--\
| 1: Ref55462 |--\\
| 2: Ref55462 |--\\\
| 3: Ref55462 |--\\\\ +−−−−−−−−−−−−−−−+
| 4: Ref55462 |---+++++->| array |
| 5: Ref55462 |--///// +−−−−−−−−−−−−−−−+
| 6: Ref55462 |--//// | length: 10 |
| 7: Ref55462 |--/// +−−−−−−−−−−−−−−−+
| 8: Ref55462 |--//
| 9: Ref55462 |--/
+−−−−−−−−−−−−−−−+

To create a 10-place array where each of the 10 places is itself a 10-place array of 0, I'd probably use either Array.from or fill with map:

// Array.from
var matrix = Array.from({length: 10}, function() {
return new Array(10).fill(0);
});

// fill and map
var matrix = new Array(10).fill().map(function() {
return new Array(10).fill(0);
});

or in ES2015:

// Array.from
let matrix = Array.from({length: 10}, () => new Array(10).fill(0));

// fill and map
let matrix = new Array(10).fill().map(() => new Array(10).fill(0));

Modifying value of matrix filled with Array.fill() modifies the whole column

That is bacause your first Array.fill call is using the same array reference to fill those 4 spots and only one inner array is created. So instead of first fill call you could use Array.from which is going to create new array for every spot.

var n = 4;
var A = Array.from(new Array(n), () => new Array(n).fill(0))
console.log(JSON.stringify(A));

A[2][2] = 4;
console.log(JSON.stringify(A)); // ..

Array.prototype.fill() different from fill as I go

Array.fill is intended to be used to fill all the elements of an array from a start index to an end index with a static value.

This unfortunately means that if you pass in an element such as a new array, your array will actually be filled with many references to that same element. In other words, a is not filled with six arrays of size six; a is filled with six pointers to the same array of size six.

You can easily verify this in your developer console:

var a = new Array(6).fill(new Array(6).fill(0));
a
>>> [Array[6], Array[6], Array[6], Array[6], Array[6], Array[6]]
a[0]
>>> [0, 0, 0, 0, 0, 0]
a[1]
>>> [0, 0, 0, 0, 0, 0]
a[0][1] = 1
a[0]
>>> [0, 1, 0, 0, 0, 0]
a[1]
>>> [0, 1, 0, 0, 0, 0]

javascript use Array fill() function to init a 2D array

That happens because dp.fill() is using a reference to the same array, defined by new Array(n).fill(false). When you change dp[0], you also "change" dp[1], dp[2], etc...

So you should use the code you posted below.

Whats the difference between Array.fill and a for loop to create Array

You can fill 2D array with a help of Array.fill in a such way:

let arr = Array(5).fill(0).map(x => Array(5).fill(0))

Fill array with objects using loop

Array.fill() takes a value and populates the array with it.
Since non-primitives (objects, arrays) are passed by reference, modification of any item will cause the rest to change as well.

Instead, you can use Array.from() and pass the object to its mapping function:

const table = Array.from({length:10}, _ => ({foo:0}));
for (let i = 0; i < table.length; i += 1) { table[i].bar = i;}
console.log(table);

How do function pointers in C work?

Function pointers in C

Let's start with a basic function which we will be pointing to:

int addInt(int n, int m) {
return n+m;
}

First thing, let's define a pointer to a function which receives 2 ints and returns an int:

int (*functionPtr)(int,int);

Now we can safely point to our function:

functionPtr = &addInt;

Now that we have a pointer to the function, let's use it:

int sum = (*functionPtr)(2, 3); // sum == 5

Passing the pointer to another function is basically the same:

int add2to3(int (*functionPtr)(int, int)) {
return (*functionPtr)(2, 3);
}

We can use function pointers in return values as well (try to keep up, it gets messy):

// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int) {
printf("Got parameter %d", n);
int (*functionPtr)(int,int) = &addInt;
return functionPtr;
}

But it's much nicer to use a typedef:

typedef int (*myFuncDef)(int, int);
// note that the typedef name is indeed myFuncDef

myFuncDef functionFactory(int n) {
printf("Got parameter %d", n);
myFuncDef functionPtr = &addInt;
return functionPtr;
}


Related Topics



Leave a reply



Submit