4

I have a javascript related question.

I have the piece of code using a spread operator

var arrObj = [{ name : "m"}, { name : "mb"}];
var arrObj1 = [...arrObj];
console.log(arrObj1); // Statement 1

arrObj1[0].name = "superman";
console.log(arrObj1);  // Statement 2
console.log(arrObj); // Statement 3

My question here is the change of name applies to both arrObj1 and arrObj. This is understandable. However, the first Statement is also displaying the value of superman instead of m. Can anyone tell me why that is. Why is the changed value of m applying to the console which is present before the value change.

enter image description here

3 Answers 3

6

The spread operator is a shallow copy operation. That means that while the arrays are separate objects, they both refer to the same element in every index. Let's provide a very simple example that illustrates this:

let a = [{ value: 'hello world' }]
let b = a;
b[0].value = 'goodbye world';
console.log(a); // [{ value: 'goodbye world' }]
console.log(b); // [{ value: 'goodbye world' }]
console.log(a===b); // true
console.log(a[0] === b[0]); // true

The === is strict equality, for objects, meaning "are two variables pointing to the same physical object in memory."

Converting this to just the spread operator, we get:

let a = [{ value: 'hello world' }]
let b = [...a];
b[0].value = 'goodbye world';
console.log(a); // [{ value: 'goodbye world' }]
console.log(b); // [{ value: 'goodbye world' }]
console.log(a===b); // false
console.log(a[0] === b[0]); // true

As you can see, the spread operator copied the array, but not the individual elements.

You can fix this by copying the elements using Array.prototype.map and the spread operator together:

let a = [{ value: 'hello world' }]
let b = a.map((v)=>({...v}));
b[0].value = 'goodbye world';
console.log(a); // [{ value: 'hello world' }]
console.log(b); // [{ value: 'goodbye world' }]
console.log(a===b); // false
console.log(a[0] === b[0]); //false

This strategy is useful for most situations, can perform better than JSON.stringify, and doesn't run in to the "circular reference" problem that you can get when dealing with recursive structures.

Do not use JSON round-trips if you want decent performance. Instead, use structuredClone, which is already available in 75% of browsers in use on the web, and well as a polyfill to fill the gap with older and otherwise unsupported browsers.

3

This is answered on stackoverflow. As per mozilla documentation

Don't use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))).

This way you are sure you are seeing the value of obj at the moment you log it. Otherwise, many browsers provide a live view that constantly updates as values change. This may not be what you want.

Alternatively:

console.log(arrObj1[0].name); // Statement 1 This will also return m
0

Use this:

var arrObj1 = JSON.parse(JSON.stringify(arrObj));

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .