【译】快速入门ES6解构以及rest参数语法

原文:gist.github.com/yang-wei/3d…javascript

写在前面

咱们首先会讨论如何在ES6中对数组以及对象使用解构(destructing)和rest参数语法。而后咱们接下来再看一些例子,而且讨论一些quiz。java

数组

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
复制代码

使用rest参数语法,能够省略参数的个数:git

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

// rest parameter
var [a, b, ...c] = array;
console.log(c);
// [3, 4]
复制代码

然而当使用rest参数的时候,你必须将它放置在最后一个位置:es6

var [...head, d] = array;
// Uncaught SyntaxError: Unexpected token...
复制代码

当解构的参数个数超过了数组中元素个数的时候,多出来的参数的值会是undefined:github

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

可是咱们能够对参数设置默认值,这样就不用担忧出现undefined啦:redux

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

咱们能够垂手可得地拷贝一个数组:数组

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

// 拷贝一个嵌套数组
var [,,,, [...clonedNestedArray]] = nestedArray;
console.log(clonedNestedArray);
// [7, 8, 9]
复制代码

还能够垂手可得地交换元素的值:微信

var a = 1, b = 2;
[b, a] = [a, b];
复制代码

这是早先JavaScript获取函数入参的代码:ide

function foo() {
  return Array.prototype.slice.call(arguments, 0);
}

foo(1,2,3,4,5) // [1, 2, 3, 4, 5]
复制代码

如今咱们能够将它重构成更精简的代码:函数

function foo(...args) {
  return args;
}

foo(1,2,3,4,5) // [1, 2, 3, 4, 5]
复制代码

对象

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"}
复制代码

若是咱们仅须要对象中的一个字段的话:

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

与数组相似,咱们一样能够对参数设置默认值:

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

// 若是对象中没有对应的key的话,将会返回undefined
var {a: A, b: B, d: D} = object;
console.log(A, B, D);
// ------- "A" "B" undefined
复制代码

若是咱们每次都要显式地书写{ keys: newVariable },那未免过于啰嗦了。因此咱们能够采用简写的形式:

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

乍一看可能会有些困惑,其实上面这段代码本质上等同于:

var {a: a, b: b, c: c} = object;
// 新的a, b, c 将会被建立
复制代码

显然,若是你想取不一样的参数名,那么就没法使用简写形式。 让咱们继续看一下其余例子:

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"

// 若是对象中没有对应的key的话,将会返回undefined
var {a, b, d} = object;
console.log(a, b, d);
// ------- "A" "B" undefined
复制代码

在解构对象的时候,同时使用rest参数语法可能会致使失败:

// 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"}
复制代码

接下来展现一下当使用对象解构语法,咱们对代码能够作到怎样的精简:

var John = {name: "John", age: 20};
var Marry = {name: "Marry"};

function getAge(person) {
  age = person.age || 18 // 默认值
  return age
}
getAge(John);  // 20
getAge(Marry); // 18

// with es6 
function getAge({age = 18}) {
  return age
}
复制代码

举例

让咱们看一下在实际编码中,解构以及rest参数语法的使用场景。首先咱们看一下函数的可变参数实现:

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

// 一个更为抽象的例子(稍微有点偏题,😁)
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
复制代码

Redux

让咱们在redux中寻找一些例子。在redux源码中,存在一个util方法 - compose,它常被用来简化代码:

function (arg) { return fn1(fn2(fn3(arg))); }
复制代码

使用compose:

function(arg) { compose(fn1, fn2, fn3)(arg) }
复制代码

让咱们看一下compose实际作了啥,这是一个精简的源码解释:

export default function compose(...funcs) {   // 接受一组函数做为入参,好比 fn1, [fn2, fn3...]
  return (...args) => { // 返回一个函数,该函数的入参好比 arg1, [arg2, arg3... ]
    // 因为使用了rest参数语法,此时args为一个数组: args = [arg1, arg2, ...]
    const last = funcs[funcs.length - 1]
    const rest = funcs.slice(0, -1)
    
    return rest.reduceRight((composed, f) => f(composed), last(...args)) 
    // (composed, f) => f(composed)没什么好说的,至关于实现函数的链式调用
    // 咱们主要解释last(...args)这部分
    // 由于咱们的函数接受的入参是last(arg1, arg2...),而不是last([arg1, arg2...])
    // 因此咱们须要确保[arg1, arg2, ...] 转变成 arg1, arg2, ...
    // 那么咱们可使用rest参数语法
  }
}
复制代码

让咱们继续看一个例子,来理解上述的args究竟是如何被转变的:

function inspect(...args) {
  // 当此函数被调用时
  // args = ["a", "b", "c"]
  
  console.log(args)  // ["a", "b", "c"]
  console.log(...args) // "a" "b" "c"
}
inspect("a", "b", "c")
复制代码

Quiz

在 ES6 JavaScript quiz 中有一些有趣的关于解构和rest参数的quiz,让咱们来看看它们吧~

Question 3

let x, { x: y = 1 } = { x }; y;
复制代码

让咱们来逐步解析:

let x, // x = undefined
   { x: y = 1 } = { x }
   // 在这里y被设置了一个默认值1
   // 又因为右边的x此时是undefined状态
   // 因此上述代码等同于:
   // { x: y = 1 } = { }
   y; // 因此y返回1
复制代码

Question 7

[...[...'...']].length
复制代码

一开始我被这段代码给吓到了。可是 '...' 本质上只是一个字符串。让咱们简化一下代码:

[...[...'str']]
复制代码

因为字符串是可遍历的,因此 ...'str' 将返回 ["s", "t", "r"] 。而后又由于 [...["s", "t", "r"]] 将返回 ["s", "t", "r"] 。因此答案很明显,那就是3啦~

Question 11

((...x, xs)=>x)(1,2,3)
复制代码

在数组那节中已经提到过了,rest参数只能放在最后一个位置,因此上述代码会抛出一个错误。

总结

这就是所有我要分享的内容啦~但愿你能经过本文快速地掌握解构以及rest参数语法的基础使用方式,Have fun!

参考资料

本文首发于kissyu.org/2018/09/11/… 欢迎评论和转载! 订阅下方微信公众号,获取第一手资讯!

相关文章
相关标签/搜索