Spread Syntax

Spread syntax can be used when all elements from an object or array need to be included in a new array or object, or should be applied one-by-one in a function call’s arguments list. There are 3 distinct places that accept the spread syntax:

  1. Function arguments list (myFunction(a, ...iterableObj, b))
  2. Array literals ([1, ...iterableObj, '4', 'five', 6])
  3. Object literals ({ ...obj, key: 'value' })

Overview

  • Spread syntax allows an iterable, such as an array expression or string to be expanded in places where arguments(for function calls) or elements (for array literals) are expected.

  • Spread syntax allows an object expression to be expanded in places where key-value pairs (for object literals) are expected. For object, Objects themselves are not iterable, but they become iterable when used in an Array, or with iterating functions such as map(), reduce(), and assign().

Spread Object

Merging Object

When merging 2 objects together with the spread operator, it is assumed another iterating function is used when the merging occurs. So following work:

const obj1 = {abc:123, def: 23, ghi: 32321};
const obj2 = {abc:'new one', def: 're new one'};
const newObj = {...obj1, ...obj2} //=> Object { abc: "new one", def: "re new one", ghi: 32321 }

But below code do not work:

const obj = {'key1': 323243};
const array = [...obj]; // TypeError: obj is not iterable 

...obj vs Object.assign()

  • Object.assign() can be used to mutate an object, whereas spread syntax can’t.
  • Object.assign() triggers setters on the target object, whereas spread syntax does not.

Conditionally adding properties to an object

const isSummer = false;
const fruits = {
  apple: 10,
  banana: 5,
  ...(isSummer ? { watermelon: 30 } : {}),
};

spread Array instead of object.

const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const merge = (...objects) => ({ ...objects });

const mergedObj = merge(obj1, obj2); // { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }

Check Rest parameter syntax!

Spread Array

let arr = [1,2,3];
let arr1 = [4,5,6];
arr1.unshift ( ...arr );// equal to : arr1.unshift ( 1, 2, 3 ); not: arr1.unshift ( 1 ); arr1.unshift ( 2); arr1.unshift ( 3 );
console.log ( arr1 ); // Array [1, 2, 3, 4, 5, 6]  

//Array.prototype.unshift.apply( arr1, arr); // Array [1, 2, 3, 4, 5, 6]

let arr2 = [4,5,6];
arr2.push ( ...arr );
console.log ( arr2 ); // Array [4, 5, 6,1,2,3], 

Below code won’t work:

let b = [3,4,5]
let c = ...b; // Error: Unexpected token '...'

There are ONLY 3 distinct places that accept the spread syntax.

Conditionally adding values to an array or an object

const isSummer = false;
const fruits = ["apple", "banana", ...(isSummer ? ["watermelon"] : [])];
// ['apple', 'banana']

Much better than:

const fruits = ["apple", "banana", isSummer ? "watermelon" : undefined];
// ['apple', 'banana', undefined]

Rest Syntax

Rest syntax looks exactly like spread syntax, but is used for destructuring arrays and objects. rest syntax is the opposite of spread syntax.

Rest parameter syntax

The rest parameter syntax allows a function to accept an indefinite number of arguments as an array, providing a way to represent variadic functions in JavaScript.

function myFun(a, b, ...manyMoreArgs) {
  console.log("manyMoreArgs", manyMoreArgs);
}
myFun("one", "two", "three", "four", "five", "six");// manyMoreArgs, ["three", "four", "five", "six"]

rest parameters vs the arguments object

One word: The arguments object is array-like object, it is not a real array, while rest parameters are Array instances.

The Differences detail:

  • The arguments object is array-like object, it is not a real array, while rest parameters are Array instances, meaning methods like sort(), map() or pop() can be applied on it directly.
  • The arguments object has the additional (deprecated) callee property.
  • In a non-strict function with simple parameters, the arguments object syncs its indices with the values of parameters. The rest parameter array never updates its value when the named parameters are re-assigned.
  • The rest parameter bundles all the extra parameters into a single array, but does not contain any named argument defined before the ...restParam. The arguments object contains all of the parameters — including the parameters in the ...restParam array — bundled into one array-like object.

destructuring assignment syntax

The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

Rest parameters is one of the implement of Destructuring. And Destructuring assignment syntax can used in many situation.

let a, b, rest;
[a, b] = [10, 20];
console.log(a);
// Expected output: 10
console.log(b);
// Expected output: 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest);
// Expected output: Array [30, 40, 50]

Similarly, you can destructure objects on the left-hand side of the assignment.

const obj = { a: 1, b: 2 };
const { a, b } = obj;
// is equivalent to:
// const a = obj.a;
// const b = obj.b;

Binding and assignment

For both object and array destructuring, there are two kinds of destructuring patterns: binding pattern and assignment pattern, with slightly different syntaxes.

  • In binding patterns, the pattern starts with a declaration keyword (var, let, or const). Then, each individual property must either be bound to a variable or further destructured.
    const obj = { a: 1, b: { c: 2 } };
    const { a } = obj; // a is constant
    let {
    b: { c: d },
    } = obj; // d is re-assignable
    
  • In assignment patterns, the pattern does not start with a keyword. Each destructured property is assigned to a target of assignment — which may either be declared beforehand with var or let, or is a property of another object — in general, anything that can appear on the left-hand side of an assignment expression.
    const numbers = [];
    const obj = { a: 1, b: 2 };
    ({ a: numbers[0], b: numbers[1] } = obj);
    // The properties `a` and `b` are assigned to properties of `numbers`
    // The parentheses ( ... ) around the assignment statement are required when using object literal destructuring assignment without a declaration.
    

Array destructuring

  • Swapping variables
    let a = 1;
    let b = 3;
    [a, b] = [b, a];
    
  • Unpacking values from a regular expression match.
    function parseProtocol(url) {
    const parsedURL = /^(\w+):\/\/([^/]+)\/(.*)$/.exec(url);
    if (!parsedURL) {
      return false;
    }
    console.log(parsedURL);
    // ["https://developer.mozilla.org/en-US/docs/Web/JavaScript",
    // "https", "developer.mozilla.org", "en-US/docs/Web/JavaScript"]
    const [, protocol, fullhost, fullpath] = parsedURL;
    return protocol;
    }
    console.log(
    parseProtocol("https://developer.mozilla.org/en-US/docs/Web/JavaScript"),
    );
    // "https"
    
  • Using array destructuring on any iterable.
    const [a, b] = new Map([
    [1, 2],
    [3, 4],
    ]);
    console.log(a, b); // [1, 2] [3, 4]
    
  • The rest binding is eagerly evaluated and creates a new array!
    const obj = {
    *[Symbol.iterator]() {
      for (const v of [0, 1, 2, 3]) {
        console.log(v);
        yield v;
      }
    },
    };
    const [a, b, ...rest] = obj; // Logs 0 1 2 3
    console.log(rest); // [2, 3] (an array)
    

Object destructuring

  • Unpacking properties from objects passed as a function parameter.
    const user = {
    id: 42,
    displayName: "jdoe",
    };
    // The parameter value { id } indicates that the id property of the object passed to the function should be unpacked into a variable with the same name, which can then be used within the function.
    function userId({ id }) {
    return id;
    }
    console.log(userId(user)); // 42
    
  • Nested object and array destructuring
    const metadata = {
    title: "Scratchpad",
    translations: [
      {
        locale: "de",
        localizationTags: [],
        lastEdit: "2014-04-14T08:43:37",
        url: "/de/docs/Tools/Scratchpad",
        title: "JavaScript-Umgebung",
      },
    ],
    url: "/en-US/docs/Tools/Scratchpad",
    };
    const {
    title: englishTitle, // rename
    translations: [
      {
        title: localeTitle, // rename
      },
    ],
    } = metadata;
    console.log(englishTitle); // "Scratchpad"
    console.log(localeTitle); // "JavaScript-Umgebung"
    

Reference

mdn doc