原文: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/… 歡迎評論和轉載! 訂閱下方微信公衆號,獲取第一手資訊!