Rest Parameters - 剩餘參數

December 22, 2015

先前記錄了 Beginning-ES6 這篇文章,裡面提到了許多 ES6 的新特性, 最近在學習的時候我遇到了一個關於 spread operator(展開運算符)的小問題,所以記錄一下。

先來講一個簡單的例子:

const myArr = ['javascript', 'php', 'python', 'ruby', 'go'];
let [one, two, ...other] = myArr;

console.log(one); // javascript
console.log(two); // php
console.log(other); // python, ruby, go

... 展開運算符在陣列上運用上相當的方便,我們來看另一個例子:

function log() {
  var things = Array.prototype.slice.call(arguments);
  things.map((thing) => console.log(thing));
}

log('error', 'sleep', 'hot', 'bad');

var things = Array.prototype.slice.call(arguments); 這個部分, 我們必須要先將 things 繼承陣列的 prototype 再使用 slicecall 將 arguments 的部分轉成陣列,其實每次看到這種長長的程式碼,我都會很害怕(弱), 但是透過展開運算符可以省去這段程式碼,我們往下看:

function log(...args) {
  args.map((thing) => console.log(thing));
}

log('error', 'sleep', 'hot', 'bad');

你會發現結果是相同的,但是下面這種透過 spread operator 的方法感覺更簡單明瞭一點, 如果感覺很抽象,不妨可以試試看 babel 官方所提供的工具 點我 可以看到前後轉換出來的差別:

function log(...args) {
  args.map((thing) => console.log(thing));
}
function log() {
  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  args.map(function (thing) {
    return console.log(thing);
  });
}

轉換後的看起來有點複雜的感覺,所以來實際看看裡面到底有些什麼:

  • arguments: 就是你在 log function 括號內的參數。
  • args = Array(_len): 產生一個新的陣列,長度是輸入參數的總長度。
function log() {
  console.log(arguments)
  ...
}

log('a', 'b', 'c'); // { '0': 'a', '1': 'b', '2': 'c' }

透過 console.log() 來查看 arguments 裡面到底是放了哪些東西, 原來是一個 key-value pair,所以在下面的這段 for 迴圈就可以比較清楚了解到了:

for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  args[_key] = arguments[_key];
}

args[_key] 對應到一個 arguments[_key]arguments[_key] 的 value 會放到 args[_key] 內, 假設如上方 log('a', 'b', 'c'),那我們查看 args 參數可以得到:['a', 'b', 'c']