d-_-b
d-_-b

Reputation: 23161

Javascript Array.map copy without changing original

I've noticed that deleting object properties when using Array.map() affects the original array, I assume since each iteration's item is still referencing the original array:

var objects = [{name: 'a', password: 'x'}, {name: 'b', password: 'x'}];

var clean = objects.map(user => {delete user.password; return user;});

console.log(JSON.stringify(objects));
> [{"name":"a"},{"name":"b"}]

Is there a way to use map or filter without it modifying the original? I can think to loop through each item and create a clone but curious if there's a simpler way.

Upvotes: 3

Views: 3002

Answers (4)

Olian04
Olian04

Reputation: 6872

This is not a problem with map or filter, these methods always return a new array. This is a problem with objects always being passed by reference in Javascript.

Consider the following:

const a = { foo: 1 }
const b = { foo: 2 }

const arr1 = [ a, b ];

const arr2 = arr1.map(v => {
  v.foo = 0;
  return v;
});

console.log(arr1);
console.log(arr2);
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)) // true

If you want to create a copy of each object in an array while doing a map you could use the spread operator:

const a = { foo: 1 }
const b = { foo: 2 }

const arr1 = [ a, b ];

const arr2 = arr1.map(v => {
  return {...v, foo: 0};
});

console.log(arr1);
console.log(arr2);
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)) // false

It's worth noting that the spread operator is a shallow clone, this means that objects within objects will still be passed by reference.

const c = { foo: 3 }
const a = { foo: 1, biz: c }
const b = { foo: 2, biz: c }

const arr1 = [ a, b, c ];

const arr2 = arr1.map(v => {
  return {...v, foo: 0};
});

console.log(arr1);
console.log(arr2);
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)) // false

Upvotes: 3

Dan
Dan

Reputation: 8784

You can map over all of the items and return only the name.

const objectsWithNames = objects.map(({name}) => ({name}));

Upvotes: 1

clabe45
clabe45

Reputation: 2454

The original array isn't being modified, but rather the items in the array (the objects) are. Since javascript objects are passed by reference, when you modify the objects in the new array, the references in the old array show the same modifications.

So, as you said, you can loop through each item and create a clone. Of course, you could perform a deep copy of the entire array too.

Upvotes: 0

Mark
Mark

Reputation: 92440

You can reference everything except password with dereferencing. Then use map to build a new object with everything else. This is nice if you have other properties on the object other than name and want to include everything except password.

var objects = [{name: 'a', password: 'x'}, {name: 'b', password: 'x'}];

var clean = objects.map(({password, ...user}) => user);

console.log(objects);  // untouched

console.log(clean);    // no password

Upvotes: 4

Related Questions