2

Something that has the same effect as:

const obj = {a:'a', b:'b', c:'c'};
const {a, b} = obj;
const result = {a, b};

Or, in ES5:

const obj = {a:'a', b:'b', c:'c'};
const result = Object.keys(obj)
    .filter((key) => ['a', 'b', 'c'].includes(key))
    .reduce((acc, key) => acc[key] = obj[key], {})

I thought

const result = { a, b } = obj;

would work, but apparently, it just has the same effect of:

const result = obj;

in that result has all of the properties of obj and it also seems to 'point' to it (result.a = 'changed' results in obj.a === changed to be true). It this a bug?

doplumi
  • 2,422
  • 4
  • 26
  • 40
  • 1
    I'd just use a library to pluck keys to create the new object, e.g., lodash. But if you also want a deep clone, then you need to deep clone. – Dave Newton Jul 29 '18 at 12:53
  • ES5 (ECMA-262 ed 5) was ECMAScript 2011. Things have moved on, the most recent version is ECMA-262 ed 9 aka ECMAScript 2018. – RobG Jul 29 '18 at 13:18
  • *"It this a bug?"* No. The result of assignment is the value that was assigned. `const result = { a, b } = obj;` is the same as `const result = ({ a, b } = obj);` where `{ a, b } = obj` is a destructuring assignment, i.e. you are assigning to two local variables `a` and `b`. You are not creating a new object. In other words, your code is equivalent to `a = obj.a; b = obj.b; const result = obj;`. – Felix Kling Jul 29 '18 at 16:13

3 Answers3

0
const result = {...obj}

Would that work? It's not deep copy but neither is your first example.

Dread Boy
  • 743
  • 6
  • 26
0

To clone an Object so it points to a different memory location, i.e. changes to either clone doesn't affect the other, you can use:

1- Object.assign():

const result = Object.assign({}, obj);

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

2.- The spread operator (in ES6):

const result = {...obj};

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

Álvaro Tihanyi
  • 1,011
  • 1
  • 7
  • 16
0

You can make your line

const result = { a, b } = obj;

work in the way that it seems you intend it to by, as others have said, using a deep copy of obj rather than referring to obj itself. One way to do this which may be the "quick one liner" you're looking for would be

const result = (({ a, b }) => ({ a, b }))(JSON.parse(JSON.stringify(obj)));

JSON.parse(JSON.stringify(obj)) just gives a deep copy of obj. Thus changes to result will not affect obj, nor vice versa.

const obj = {a:'a', b:'b', c:'c'};
const result = (({ a, b }) => ({ a, b }))(JSON.parse(JSON.stringify(obj)));
console.log(result);//expected output: Object { a: "a", b: "b" }

result.a = 'changed';
console.log(result);//expected output: Object { a: "changed", b: "b" }
console.log(obj);//expected output: Object { a: "a", b: "b", c: "c" }

Some performance info on this method of deep copy is shared in this SO answer, and that thread has some alternatives.

An explanation of the syntax of the object destructuring syntax can be found in this SO answer.

kenS
  • 344
  • 1
  • 11
  • At first I misunderstood what you were going for. I've edited my answer to reflect what I think you're after now that I think I understand better. – kenS Jul 29 '18 at 13:32
  • 1
    *"JSON.parse(JSON.stringify(obj)) just gives a deep copy of obj."* But throws away everything that cannot be encoded as JSON. – Felix Kling Jul 29 '18 at 16:10
  • @Felix Kling yes, perhaps most notably keys with functions as their values and date objects. (This is discussed in more depth in the SO thread that I linked in my answer which contains discussion and alternatives about deep cloning methods) – kenS Jul 30 '18 at 02:03