Search code examples
javascriptecmascript-6destructuring

Object destructuring into another object does not work


Today I had to merge two objects, picking the properties of an object a and placing them in an object b. I can't understand why the first syntax/statement is not working, while the second one is.

let user = { a: 1, b: 2 };
let data = { z: 1, c: 3, f: 8, d: 4 };

// Let's say I want user to be { a: 1, b: 2, c: 3}

// method 1 (not works) 
const r1 = {
    ...user,
    ...({c} = data)
};
document.getElementById("r1").innerText = JSON.stringify(r1);

// method 2 (works)
const r2 = {
    ...user,
    ...(({c}) => ({c}))(data)
};
document.getElementById("r2").innerText = JSON.stringify(r2);

You can try the code on https://jsfiddle.net/Ljb7ndp4/6/


Solution

  • In the second method you are creating an IIFE (Immediately Invoked Function Expression).

    From MDN docs, "an IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined". The IIFE on method 2 is returning an object like {c: <value>}. As objects support the spread operator, you are able to use it in the object definition.

    To visualize it in your code, you can assign the result of the IIFE to a variable and print the result on console.

    const val = (({c}) => ({c}))(data)
    console.log(val) // { c: 3 }
    

    The arrow function syntax, in this case, makes a little bit harder to visualize what is happening, but the code:

    (({c}) => ({c}))(data);
    

    is a short version of this one, which is better readable, in my opinion.

    (function(arg) {
      return { c: arg.c }
    })(data);
    

    So, we can convert it to arrow function to understand all the transformations, step by step.

    Initially we can convert the function to use the arrow function syntax:

    ((arg) => {
      return { c: arg: c }
    })(data)
    

    Then we can destructur c from the received argument.

    (({c}) => {
      return { c: c }
    })(data)
    

    As the created arrow function does not require a block, we can simplify it:

    // The parenthesis are added because the syntax () => {} is not valid.
    (({c}) => ({ c: c }))(data)
    

    And finally, we can use the short object syntax to make it exactly as the original one.

    (({c}) => ({ c }))(data)
    

    So, this function generates a { c: <value> } object, and therefore you can use the spread operator to merge it in the object you are building.