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  9We 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);
// undefinedBut we can always back it up by set its default value
var [a, b, c, d, e = 5] = array;
console.log(e);
// -------- 5We 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];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" undefinedUsing 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 = 1Let'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)
// 6Let'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")
First of all, nice gist!
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 } = objectwhere
console.log(A, B, C)outputsA B {c: "C"}