Is it possible to destructure onto an existing object? (Javascript ES6)

79,273

Solution 1

While ugly and a bit repetitive, you can do

({x: oof.x, y: oof.y} = foo);

which will read the two values of the foo object, and write them to their respective locations on the oof object.

Personally I'd still rather read

oof.x = foo.x;
oof.y = foo.y;

or

['x', 'y'].forEach(prop => oof[prop] = foo[prop]);

though.

Solution 2

IMO this is the easiest way to accomplish what you're looking for:

let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };

  // data === { prop1: someObject.prop1, ... }

Basically, destructure into variables and then use the initializer shorthand to make a new object. No need for Object.assign

I think this is the most readable way, anyways. You can hereby select the exact props out of someObject that you want. If you have an existing object you just want to merge the props into, do something like this:

let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
    // Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
    // Merges into otherObject

Another, arguably cleaner, way to write it is:

let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };

// Merges your selected props into otherObject
Object.assign(otherObject, newObject);

I use this for POST requests a lot where I only need a few pieces of discrete data. But, I agree there should be a one liner for doing this.

EDIT: P.S. - I recently learned you can use ultra destructuring in the first step to pull nested values out of complex objects! For instance...

let { prop1, 
      prop2: { somethingDeeper }, 
      prop3: { 
         nested1: {
            nested2
         } 
      } = someObject;
let data = { prop1, somethingDeeper, nested2 };

Plus, you could use spread operator instead of Object.assign when making a new object:

const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };

Or...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };

Solution 3

No, destructuring does not support member expressions in shorthands but only plain propertynames at the current time. There have been talks about such on esdiscuss, but no proposals will make it into ES6.

You might be able to use Object.assign however - if you don't need all own properties, you still can do

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}

Solution 4

Other than Object.assign there is the object spread syntax which is a Stage 2 proposal for ECMAScript.

    var foo = {
      x: "bar",
      y: "baz"
    }
    
    var oof = { z: "z" }
    
    oof =  {...oof, ...foo }
    
    console.log(oof)

    /* result 
    {
      "x": "bar",
      "y": "baz",
      "z": "z"
    }
    */

But to use this feature you need to use stage-2 or transform-object-rest-spread plugin for babel. Here is a demo on babel with stage-2

Solution 5

BabelJS plugin

If you are using BabelJS you can now activate my plugin babel-plugin-transform-object-from-destructuring (see npm package for installation and usage).

I had the same issue described in this thread and for me it was very exhausting when you create an object from a destructuring expression, especially when you have to rename, add or remove a property. With this plugin maintaining such scenarios gets much more easier for you.

Object example

let myObject = {
  test1: "stringTest1",
  test2: "stringTest2",
  test3: "stringTest3"
};
let { test1, test3 } = myObject,
  myTest = { test1, test3 };

can be written as:

let myTest = { test1, test3 } = myObject;

Array example

let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
  myTest = [ test1, test3 ];

can be written as:

let myTest = [ test1, , test3 ] = myArray;
Share:
79,273

Related videos on Youtube

tnrich
Author by

tnrich

Updated on January 31, 2021

Comments

  • tnrich
    tnrich over 3 years

    For example if I have two objects:

    var foo = {
      x: "bar",
      y: "baz"
    }
    

    and

    var oof = {}
    

    and I wanted to transfer the x and y values from foo to oof. Is there a way to do that using the es6 destructuring syntax?

    perhaps something like:

    oof{x,y} = foo
    
    • elclanrs
      elclanrs about 9 years
      If you want to copy all properties Object.assign(oof, foo)
    • jfriend00
      jfriend00 about 9 years
      Lots of destructing examples here on MDN, but I do not see the one you're asking about.
    • tnrich
      tnrich about 9 years
      Hmm I couldn't find one either..
    • Zfalen
      Zfalen about 7 years
      See my answer below for a two line solution without Object.assign
  • jpierson
    jpierson over 8 years
    @loganfsmyth, your example isn't working for me at least in my tests with node 4.2.2. with --harmony_destructuring enabled. I see "SyntaxError: Unexpected token ."
  • Theo.T
    Theo.T almost 8 years
    Sadly it seems like oof just receives a reference of foo and bypasses the whole destructuring (at least in Chrome). oof === foo and let oof = { x } = foo yet returns { x, y }
  • user1577390
    user1577390 almost 8 years
    @Theo.T good catch. that's a bummer, i'll have to find another way
  • Sulliwane
    Sulliwane over 7 years
    @loganfsmyth you should submit a proper answer as this is a very useful comment imo.
  • Matt Browne
    Matt Browne over 7 years
    This doesn't actually set the properties on the existing object, but rather creates a new object containing all the properties of both.
  • Vladimir Brasil
    Vladimir Brasil over 7 years
    The alternative ['x', 'y'].forEach(prop => oof[prop] = foo[prop]); as I see, is the only one D.R.Y (do not repeat yourself), till now. "DRY" would be indeed useful in the case of several keys to be mapped. You would only need to update one place. Maybe I am wrong. Thanks anyway!
  • Jeff Lowery
    Jeff Lowery over 6 years
    Third example is DRY, but you have to use strings as the keys, which javascript normally does implicitly. Not convinced that's less of a nuisance than: const {x, y} = foo; const oof = {x, y};
  • techguy2000
    techguy2000 over 6 years
    Can someone show me in jsfiddle where the first suggestion works? It's not working here on chrome: jsfiddle.net/7mh399ow
  • loganfsmyth
    loganfsmyth over 6 years
    @techguy2000 You forgot the semicolon after var oof = {};.
  • Jesse
    Jesse over 6 years
    I like this approach, pragmatic.
  • jgmjgm
    jgmjgm over 6 years
    This is what I do but it's not very dry. I think what a lot of people really need is just an extract keys function.
  • jgmjgm
    jgmjgm over 6 years
    This ones worth keeping just for demonstrating how JS can be confusing.
  • T.J. Crowder
    T.J. Crowder over 6 years
    @Sulliwane: He's done so (now). Bergi, would probably be best to update the answer to call out that you can use member expressions as shown by Logan. (Is it really true that the spec changed that much between April and June 2015?)
  • Bergi
    Bergi over 6 years
    @T.J.Crowder No, I don't think it changed, I guess I was talking about {oof.x, oof.y} = foo. Or maybe I really had missed it.
  • Zfalen
    Zfalen about 6 years
    @jgmjgm yeah, it would be nice to have one built in but I guess thats not too hard to write either.
  • Sornii
    Sornii almost 6 years
    In the first code, shouldnt be ({x: oof.x, y: oof.y} = foo) ? I think you've put an extra f in oof.
  • loganfsmyth
    loganfsmyth almost 6 years
    @Sornii Thanks, fixed!
  • tnrich
    tnrich over 4 years
    I think this first case is exactly what I was looking for. I tried it out in the chrome console and it seems to work. Cheers! @campsafari
  • loganfsmyth
    loganfsmyth over 4 years
    @majorBummer Your call in the end, but I'd consider approach to not actually answer your question, because these both create new objects, rather than adding properties to existing objects like your title asks.
  • tnrich
    tnrich over 4 years
    That's a good point @loganfsmyth. I think I was just excited by the method campSafari brought up because I hadn't realized that that was possible.
  • garrettmaring
    garrettmaring over 4 years
    This is precisely what I wanted. Thank you!
  • Joshua Coady
    Joshua Coady over 4 years
    If you dont mind creating a new object you could just do oof = {...oof, ...foo}
  • Eatdoku
    Eatdoku almost 4 years
    let myTest = { test1, test3 } = myObject; doesn't work
  • Hielke Walinga
    Hielke Walinga almost 4 years
    Most JS formatters will change ( in the beginning of the line to ;( which I think is a pretty clean solution to those kind of problems and you still can just omit the semicolons after each line.
  • Nitsan Avni
    Nitsan Avni over 3 years
    can do Object.keys(foo).forEach(prop => oof[prop] = foo[prop]);
  • Giorgio Tempesta
    Giorgio Tempesta over 3 years
    I personally like the syntax of the first example when changing from one case style to another, like this: ({ order_number: this.orderNumber, order_amount: this.orderAmount } = this.config);
  • Ecksters
    Ecksters about 3 years
    @JoshuaCoady ...= operator when?
  • Slbox
    Slbox over 2 years
    This works in every browser I test, but doesn't seem to work with Babel/Webpack.