『ES6腳丫系列』擴展運算符spread和rest參數

圖片.png

『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

img


例子:

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]

用途:

【01】複製數組

slice()是JS數組的一個方法,它能夠複製數組,相似的,可使用擴展運算符來複制數組:

arr2並不等於arr。由於不是相等操做,它們引用的地址不同。

var arr = ['a', 'b', 'c'];
var arr2 = [...arr];
console.log(arr2);// ['a', 'b', 'c']

【02】鏈接數組

可使用擴展運算符替代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']

【03】Math

能夠在使用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

【04】字符串轉換數組

使用擴展運算符將字符串轉換成數組。

var str = "hello";
var chars = [...str];
console.log(chars); // ['h', 'e',' l',' l', 'o']

【05】可以把可迭代對象(NodeList, arguments等等)轉化爲真正的數組。

// 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']

【02】散佈操做符 (…)

概念

【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

圖片.png

計算這個參數總和的一種方法是將其轉換成具備 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'
相關文章
相關標籤/搜索