Skip to content

Instantly share code, notes, and snippets.

@yang-wei
Last active April 23, 2025 00:35
Show Gist options
  • Save yang-wei/3d35e8692dbc6cc0f98d to your computer and use it in GitHub Desktop.
Save yang-wei/3d35e8692dbc6cc0f98d to your computer and use it in GitHub Desktop.
ES6 destructing (and rest parameter)

arrays

var array = [1, 2, 3, 4];
var nestedArray = [1, 2, 3, 4, [7, 8, 9]];

var [a, b, c, d] = array;
console.log(a, b, c, d)
// -------- 1  2  3  4

var [a, , , d, [x, y, z]] = nestedArray;
console.log(a, d, x, y, z)
// -------- 1  4  7  8  9

We don't have to match the full array

var [a, b, c] = array;
console.log(a, b, c)
// -------- 1  2  3

// rest
var [a, b, ...c] = array;
console.log(c);
// [3, 4]

When destructing variable exceeds its matched array, undefined is returned

var [a, b, c, d, e] = array;
console.log(e);
// undefined

But we can always back it up by set its default value

var [a, b, c, d, e = 5] = array;
console.log(e);
// -------- 5

We can clone array easily

var [...clonedArray] = array;
console.log(clonedArray);
// [1, 2, 3, 4]

// clone the nested one
var [,,,, [...clonedNestedArray]] = nestedArray;
console.log(clonedNestedArray);
// [7, 8, 9]

Swap variable like a boss

var a = 1, b = 2;
[b, a] = [a, b];

Object

var object = {a: "A", b: "B", c: "C"};
var nestedObject = {a: "A", b: "B", c: "C", x: {y: "Y", z: "Z"}};

var {a: A, b: B, c: C} = object;
console.log(A, B, C);
// ------ "A" "B" "C"

var {a: A, b: B, c: C, x: X} = nestedObject;
console.log(X);
// {y: "Y", z: "Z"}

When we only need a value

var {b: B} = object;
console.log(B);
// ------- "B"

Similar to array, we can set a default value

var {b: B, d: D = "D"} = object;
console.log(B, D);
// ------- "B" "D"

// and it returns undefined when keys are not match
var {a: A, b: B, d: D} = object;
console.log(A, B, D);

For everytime we have to write { keys: newVariable } explicit this is very verbose. Let's enter short hand method:

var {a, b, c} = object;
console.log(a, b, c);
// -------"A" "B" "C"

It might seems confuse at first but this is the short hand of

var {a: a, b: b, c: c} = object;
// new variables a, b, c are created

Do not use short hand method if you want to create different variable name.

Continueing on other examples:

var object = {a: "A", b: "B", c: "C"};
var nestedObject = {a: "A", b: "B", c: "C", x: {y: "Y", z: "Z"}};


var {a, b, c, x} = nestedObject;
console.log(x);
// { y: "Y", z: "Z" }


var {b} = object;
console.log(b);
// ------- "B"

var {b, d = "D"} = object;
console.log(d, d);
// ------- "B" "D"

// and it returns undefined when keys are not match
var {a, b, d} = object;
console.log(a, b, d);
// ------- "A" "B" undefined

Using rest in object destructing failed =(

// error
// var {a: A, b: B, c: ...C} = object;
// console.log(A, B, C);   <-- error
// use the shorthand method

var {a, b, ...c} = object;  // es7
console.log(c);
// {c: "C"}

// be careful with some reserved property name

var [length] = ["a", "b", "c"];
console.log(length)
// 1 because a.length = 1

Let's see some pratical usage. Eg: optional arguments for functions

function sum(...numbers) {
  return numbers.reduce((n, total) => {
    return n + total
  }, 0);
}
sum();   // 0
sum(1, 2, 3);   // 6
sum(1, 2, 3, 4, 5);   // 15

// more abstraction <-- out of topic
function math(equation, ...numbers) {
  return numbers.reduce((n, total) => {
    return equation.call(null, n, total);
  });
}

const add = (a, b) => { return a + b; }
let sum1 = math(add, 1, 2, 3, 4);
// 10

const times = (a, b) => { return a * b; }
let product1 = math(times, 1, 2, 3)
// 6

Example on OSS

Let's look at some example on some great open source project - redux. In redux source code there is a utils function - compose which is used to turn our verbose code into a nicer one.

function (arg) { return fn1(fn2(fn3(arg))); }

into

function(arg) { compose(fn1, fn2, fn3)(arg) }

Here is the shorten source code and explaination

export default function compose(...funcs) {   // here, a list of function(s) is expected: fn1, [fn2, fn3...]
  return (...args) => { // it return a composed function which expects a list of argument(s): arg1, [arg2, arg3... ]
    // args is now an array: args = [arg1, arg2, ...]
    const last = funcs[funcs.length - 1]
    const rest = funcs.slice(0, -1)
    
    return rest.reduceRight((composed, f) => f(composed), last(...args)) 
    // the first part in reduce right is not so interesting, we just keep chaining functions
    // in the second part - last(...args)
    // since our last function will accept argument like last(arg1, arg2...) instead of last([arg1, arg2...])
    // we turn [arg1, arg2, ...] into arg1, arg2, ...
    // by using rest
  }
}

To simplify how the args being changed:

function inspect(...args) {
  // when this function is called
  // args = ["a", "b", "c"]
  
  console.log(args)  // ["a", "b", "c"]
  console.log(...args) // "a" "b" "c"
}
inspect("a", "b", "c")
@peksipatongeis
Copy link

First of all, nice gist!

Using rest in object destructing failed =(

// error
// var {a: A, b: B, c: ...C} = object;
// console.log(A, B, C); <-- error
// use the shorthand method

Related to the piece of code above, destructuring with rest operator should work just fine. It just works a bit differently as you are already naming the rest with the operator.

So you could have this instead:

let { a: A, b: B, ...C } = object

where console.log(A, B, C) outputs A B {c: "C"}

@GMartigny
Copy link

Hi @yang-wei,
Great article about the subject with comprehensible examples, nice job.

I have a little nitpick about the last example

function sum(...numbers) {
  return numbers.reduce((total, n) => {			// The parameters order was wrong https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Parameters
    return n + total;
  }, 0);
}
sum();   // 0
sum(1, 2, 3);   // 6
sum(1, 2, 3, 4, 5);   // 15

// more abstraction <-- out of topic
function math(equation, ...numbers) {
  return numbers.reduce(equation);				// .call was not necessary, removing it allow to pass equation directly
}

const add = (a, b) => a + b;					// if return is on the same line, no need for braces {}
let sum1 = math(add, 1, 2, 3, 4);
// 10

const times = (a, b) => a * b;					// same here
let product1 = math(times, 1, 2, 3);
// 6

You should consider posting this kind of work under a proper blogging plateforme like Dev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment