【譯】快速入門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/… 歡迎評論和轉載! 訂閱下方微信公衆號,獲取第一手資訊!

相關文章
相關標籤/搜索