原文: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源码中,存在一个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")
复制代码
在 ES6 JavaScript quiz 中有一些有趣的关于解构和rest参数的quiz,让咱们来看看它们吧~
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
复制代码
[...[...'...']].length
复制代码
一开始我被这段代码给吓到了。可是 '...'
本质上只是一个字符串。让咱们简化一下代码:
[...[...'str']]
复制代码
因为字符串是可遍历的,因此 ...'str'
将返回 ["s", "t", "r"]
。而后又由于 [...["s", "t", "r"]]
将返回 ["s", "t", "r"]
。因此答案很明显,那就是3啦~
((...x, xs)=>x)(1,2,3)
复制代码
在数组那节中已经提到过了,rest参数只能放在最后一个位置,因此上述代码会抛出一个错误。
这就是所有我要分享的内容啦~但愿你能经过本文快速地掌握解构以及rest参数语法的基础使用方式,Have fun!
本文首发于kissyu.org/2018/09/11/… 欢迎评论和转载! 订阅下方微信公众号,获取第一手资讯!