『ES6腳丫系列』擴展運算符spread和rest參數數組
學習就比如是座大山,人們沿着不一樣的路爬山,分享着本身看到的風景。你不必定能看到別人看到的風景,體會到別人的心情。只有本身去爬山,才能看到不同的風景,體會才更加深入。
【01】又叫作展開運算符。app
【02】spread 運算符和 rest 參數相反。函數
三個點: ...學習
將一個數組或一個可迭代的對象,在一次調用中,將它們的內容分隔爲單個單個的成員參與運算。ui
若是是數組:this
等同於將一個數組去掉外層的方括號,而後總體放在原先的位置同樣。
逗號分隔的參數列表。
若是是字符串:spa
等同於,變爲單個字符單個字符用逗號分隔的參數列表。let res = [..."hel"];//["h","e","l"];prototype
若是是可迭代對象:(只有部署了iterator的對象纔是可迭代的)rest
把屬性變爲用逗號分隔的參數列表。
例子:code
let array = ['one', 'two', 'three'] // These two are exactly the same console.log(...array) // one two three console.log('one', 'two', 'three') // one two three
例子:
var middle = [3, 4]; var arr = [1, 2, middle, 5, 6]; console.log(arr);// [1, 2, [3, 4], 5, 6]
只想要一個數組呢?
var middle = [3, 4]; var arr = [1, 2, ...middle, 5, 6]; console.log(arr);// [1, 2, 3, 4, 5, 6]
slice()是JS數組的一個方法,它能夠複製數組,相似的,可使用擴展運算符來複制數組:
arr2並不等於arr。由於不是相等操做,它們引用的地址不同。
var arr = ['a', 'b', 'c']; var arr2 = [...arr]; console.log(arr2);// ['a', 'b', 'c']
可使用擴展運算符替代concat()來鏈接數組。
首先,咱們來看看concat()方法是如何實現的。
var arr = ['a', 'b', 'c']; var arr2 = ['d', 'e', 'f']; arr1 = arr.concat(arr2); console.log(arr);// ['a', 'b', 'c', 'd', 'e', 'f']
使用擴展運算符:
var arr = ['a', 'b', 'c']; var arr2 = ['d', 'e', 'f']; arr = [...arr, ...arr2]; console.log(arr);// ['a', 'b', 'c', 'd', 'e', 'f']
能夠在使用math函數時結合擴展運算符。
例子。
Math.max()會返回一堆數字中最大的數。
Math.max();// -Infinity Math.max(1, 2, 3);// 3 Math.max(100, 3, 4);// 100
若是不使用擴展運算符,最簡單的方式是使用.apply(),將一個數組做爲參數傳入Math.max()
var arr = [2, 4, 8, 6, 0]; function max(arr) { return Math.max.apply(null, arr); } console.log(max(arr));// 8
這樣作很麻煩。
如今來看一下如何使用擴展運算符來獲得相同的結果的。只須要兩行代碼:
var arr = [2, 4, 8, 6, 0]; var max = Math.max(...arr); console.log(max);// 8 let numbers = [9, 4, 7, 1]; Math.min(...numbers); // 1
使用擴展運算符將字符串轉換成數組。
var str = "hello"; var chars = [...str]; console.log(chars); // ['h', 'e',' l',' l', 'o']
// Convert NodeList to Array let divsArray = [...document.querySelectorAll('div')]; // Convert Arguments to Array let argsArray = [...arguments];
下面的例子使得一個類數組對象符合迭代協議,並利用spread運算符將其轉變爲一個數組:
function iterator() { var index = 0; return { next: () => ({ // Conform to Iterator protocol done : index >= this.length, value: this[index++] }) }; } var arrayLike = { 0: 'Cat', 1: 'Bird', length: 2 }; arrayLike[Symbol.iterator] = iterator; //Conform to Iterable Protocol var array = [...arrayLike]; console.log(array); // => ['Cat', 'Bird']
【01】rest參數。用三個點表示。
【02】rest 參數意味着把剩下的東西包裝成一個數組。
【03】用在函數參數和解構數組中。
它將一個逗號分隔的參數列表轉換成一個數組。
吃碼小妖:相似打包和解壓的既視感?
若是在函數形參中使用了rest參數(打包),那麼在函數中使用spread使用它(解壓),等於原封不動的使用實參了。
【04】當三個點出如今函數參數時,它意味着將調用函數時的參數列表變爲一個數組。該參數名就是這個數組。
若是函數參數自己就是一個數組,那麼rest參數運算符等於把函數形參變爲一個二維數組了。
例子:
function a(...args){} a(1,2,3,4,5);
等同於
function a(){ var args = [arguments[0],arguments[1],...,arguments[N]]; }; a(1,2,3,4,5);
【05】若是是多個形參,那麼rest參數須要是參數列表中的最後一個參數。寫成逗號分隔的參數列表。
arguments對象不具備這種選擇性而且始終包含全部的參數值。
例子:
function filter(type, ...items) { return items.filter(item => typeof item === type); } filter('boolean', true, 0, false); // => [true, false] filter('number', false, 4, 'Welcome', 7); // => [4, 7]
【01】使用不定數量的函數參數。
在ES5中,當咱們須要處理一個未知數量的參數的函數時,可使用arguments變量。
function sum () { console.log(arguments) } sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//55
計算這個參數總和的一種方法是將其轉換成具備 Array.prototype.slice.call(arguments) 的數組,而後用數組方法循環遍歷每一個數字,如 forEach 或 reduce。
我相信你能夠本身實現 forEach ,因此這裏是 reduce 的例子:
// ES5 way function sum () { let argsArray = Array.prototype.slice.call(arguments); return argsArray.reduce(function(sum, current) { return sum + current; }, 0) }
使用 ES6 rest 參數,能夠將全部逗號分隔的參數直接打包到數組中。
// ES6 way const sum = (...args) => args.reduce((sum, current) => sum + current, 0) // ES6 way if we didn't shortcut it with so many arrow functions function sum (...args) { return args.reduce((sum, current) => sum + current, 0) }
【】在數組解構中遇到三個點。它會將剩餘的元素打包變爲一個數組。
let scores = ['98', '95', '93', '90', '87', '85'] let [first, second, third] = scores console.log(first) // 98 console.log(second) // 95 console.log(third) // 93
若是咱們想要 rest 的分數,咱們能夠經過將剩餘的分數打包成一個數組。
let scores = ['98', '95', '93', '90', '87', '85'] let [first, second, third, ...restOfScores] = scores console.log(restOfScores) // [90, 97, 95]
用途2:在數組中插入不定數量的元素。
例如,.push(item1, ..., itemN)會把元素一個接一個的插入數組:不得不循環每一個元素將其做爲參數。但這並不老是很方便:有時須要把一整個數組的元素push到目標數組。
在ES5中這能夠經過.apply()作到:用一種不友好且繁瑣的方式。讓咱們看看:
var fruits = ['banana']; var moreFruits = ['apple', 'orange']; Array.prototype.push.apply(fruits, moreFruits); console.log(fruits); // => ['banana', 'apple', 'orange'] ES6:let res = fruits.push(...moreFruits);console.log(res);// ['banana', 'apple', 'orange']
【】如何更好的把數組中的元素做爲參數填充到函數調用中。
ES5在函數對象上提供了 .apply()來解決這個問題。不幸的是這項技術有3個問題:
例子:
let countries = ['Moldova', 'Ukraine']; countries.push.apply(countries, ['USA', 'Japan']); console.log(countries); // => ['Moldova', 'Ukraine', 'USA', 'Japan']
例子:
function spreadReporter(...values) { let object = [...values]; return object[0].length; } var items = ['one', 'two', 'three']; console.log(spreadReporter(items)); // 3
例子:
let dairy = []; let store = { add: function(category, ...items) { category.push(...items); } }; store.add(dairy, 'milk', 'sour cream'); store.add(dairy, 'ice cream', 'yogurt', 'cheese'); console.log(dairy); // outputs ["milk", "sour cream", "ice cream", "yogurt", "cheese"]
在複雜情景中的函數體內操做arguments對象是很麻煩的。
爲了在filterNumbers()訪問sumOnlyNumbers()的arguments,你不得不建立一個臨時變量args。這是由於filterNumbers()會定義它本身的arguments從而覆蓋了外層的arguments。
這種方式能夠工做,可是太繁瑣了。
function sumOnlyNumbers() { function filterNumbers() { return Array.prototype.filter.call(args, element => typeof element === 'number'); } var args = arguments; var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); } sumOnlyNumbers(1, 'Hello', 5, false); // => 6
rest運算符能夠優雅的解決這個問題。它容許你在函數聲明時定義一個rest參數...args:
function sumOnlyNumbers(...args) { var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return args.filter(element => typeof element === 'number'); } } sumOnlyNumbers(1, 'Hello', 5, false); // => 6
函數聲明function sumOnlyNumbers(...args)代表args以數組的形式接受調用參數。
【】箭頭函數並不定義本身的arguments而是會訪問外層做用域中的arguments對象。
例子:
(function() { let outerArguments = arguments; const concat = (...items) => { console.log(arguments === outerArguments); // => true return items.reduce((result, item) => result + item, ''); }; concat(1, 5, 'nine'); // => '15nine' })();
Spread運算符能夠在構造器調用中使用數組元素做爲參數,而這並不能經過直接使用.apply()作到。
讓咱們看一個例子:
class King { constructor(name, country) { this.name = name; this.country = country; } getDescription() { return `${this.name} leads ${this.country}`; } } var details = ['Alexander the Great', 'Greece']; var Alexander = new King(...details); Alexander.getDescription(); // => 'Alexander the Great leads Greece'