Search code examples
javascriptspread-syntax

Spread operator with objects


i was trying to solve this problem in javascript : Write a function that takes an object as argument containing properties with personal information .Extract firstName, lastName, size, and weight if available .If size or weight is given transform the value to a string .Attach the unit cm to the size .Attach the unit kg to the weight .Return a new object with all available properties that we are interested in .So i gave this solution :

function myFunction(obj) {
const {fn:fn , ln:ln ,size:s ,weight:w}= obj;
var newObj= {fn:fn , ln:ln};
if (s!==undefined && w!==undefined){
    newObj={fn:fn , ln:ln ,size:s.toString()+'cm' ,weight:w.toString()+'kg'};
}
else if(s===undefined || w===undefined){
    if (s===undefined && w!==undefined){
        newObj={fn:fn , ln:ln ,weight:w.toString()+'kg'};
    }
    else if (s!==undefined && w===undefined) {
        newObj={fn:fn , ln:ln ,size:s.toString()+'cm'};
    }
}
return newObj

}

And the author's solution was :

function myFunction(obj) {
return {
  fn: obj.fn,
  ln: obj.ln,
  ...(obj.size && { size: `${obj.size}cm` }),
  ...(obj.weight && { weight: `${obj.weight}kg` }),
};

}

Can someone explain to me (or refer me to where i can find the answer) the lines with the spread operator and why does that work when the value of weight or size is undefined ? Thank you


Solution

  • There are a couple of things going on there:

    • Object spread syntax (it's not an operator) allows you to "spread" the values null and undefined. When you do, no properties are added to the object being created. (This is just like Object.assign, which ignores null and undefined in its argument list.)

    • The && operator accepts two operands, evaluates the first, and if that value is falsy, takes that value as its result; it only evaluates the second operand and takes it as its result if the first value is truthy.

    Taking those two things together, in the object literal, the ...(obj.size && { size: `${obj.size}cm` }) part works like this: if obj.size is undefined, it's basically ...undefined which doesn't add any properties to the object. But if obj.size is truthy, the second operand { size: `${obj.size}cm` } (an object literal) is evaluated, results in an object, and you end up with ...{ size: `${obj.size}cm` } which adds a size property to the object being created.

    Note: If obj.size is 0, there will be no size property on the result, because 0 is falsy. So the author may well be incorrectly dropping size or weight with that solution:

    function myFunction(obj) {
        return {
            fn: obj.fn,
            ln: obj.ln,
            ...(obj.size && { size: `${obj.size}cm` }),
            ...(obj.weight && { weight: `${obj.weight}kg` }),
        };
    }
    
    console.log(myFunction({fn: "fn", ln: "ln", size: 0}));

    When obj.size is 0, you end up with ...0 in the object, which (in theory) creates a Number object (rather than primitive) from the primitive 0 then spreads its properties. It doesn't put any properties in the object because, by default, Number objects don't have any own, enumerable properties.

    Now, if the problem is defined such that size and weight will never be 0, fair enough. But I would think carefully before generalizing that solution.