『ES6腳丫系列』擴(kuò)展運(yùn)算符spread和rest參數(shù)

圖片.png

『ES6腳丫系列』擴(kuò)展運(yùn)算符spread和rest參數(shù)

學(xué)習(xí)就好比是座大山,人們沿著不同的路登山,分享著自己看到的風(fēng)景。你不一定能看到別人看到的風(fēng)景,體會到別人的心情。只有自己去登山,才能看到不一樣的風(fēng)景,體會才更加深刻。

擴(kuò)展運(yùn)算符(...)

概念

【01】又叫做展開運(yùn)算符。

【02】spread 運(yùn)算符和 rest 參數(shù)相反。

語法

三個(gè)點(diǎn): ...

將一個(gè)數(shù)組或一個(gè)可迭代的對象,在一次調(diào)用中,將它們的內(nèi)容分隔為單個(gè)單個(gè)的成員參與運(yùn)算。

如果是數(shù)組:

等同于將一個(gè)數(shù)組去掉外層的方括號,然后整體放在原先的位置一樣。
逗號分隔的參數(shù)列表。

如果是字符串:

等同于,變?yōu)閱蝹€(gè)字符單個(gè)字符用逗號分隔的參數(shù)列表。

let res = [..."hel"];//["h","e","l"];

如果是可迭代對象:(只有部署了iterator的對象才是可迭代的)

把屬性變?yōu)橛枚禾柗指舻膮?shù)列表。

例子:

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]

只想要一個(gè)數(shù)組呢?

var middle = [3, 4];
var arr = [1, 2, ...middle, 5, 6];
console.log(arr);// [1, 2, 3, 4, 5, 6]

用途:

【01】復(fù)制數(shù)組

slice()是JS數(shù)組的一個(gè)方法,它可以復(fù)制數(shù)組,類似的,可以使用擴(kuò)展運(yùn)算符來復(fù)制數(shù)組:

arr2并不等于arr。因?yàn)椴皇窍嗟炔僮?,它們引用的地址不一樣?/p>

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

【02】連接數(shù)組

可以使用擴(kuò)展運(yùn)算符替代concat()來連接數(shù)組。

首先,我們來看看concat()方法是如何實(shí)現(xiàn)的。

var arr = ['a', 'b', 'c'];
var arr2 = ['d', 'e', 'f'];

arr1 = arr.concat(arr2);
console.log(arr);// ['a', 'b', 'c', 'd', 'e', 'f']

使用擴(kuò)展運(yùn)算符:

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函數(shù)時(shí)結(jié)合擴(kuò)展運(yùn)算符。

例子。

Math.max()會返回一堆數(shù)字中最大的數(shù)。

Math.max();// -Infinity
Math.max(1, 2, 3);// 3
Math.max(100, 3, 4);// 100

如果不使用擴(kuò)展運(yùn)算符,最簡單的方式是使用.apply(),將一個(gè)數(shù)組作為參數(shù)傳入Math.max()

var arr = [2, 4, 8, 6, 0];
function max(arr) {
  return Math.max.apply(null, arr);
}
console.log(max(arr));// 8

這樣做很麻煩。

現(xiàn)在來看一下如何使用擴(kuò)展運(yùn)算符來得到相同的結(jié)果的。只需要兩行代碼:

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】字符串轉(zhuǎn)換數(shù)組

使用擴(kuò)展運(yùn)算符將字符串轉(zhuǎn)換成數(shù)組。

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

【05】能夠把可迭代對象(NodeList, arguments等等)轉(zhuǎn)化為真正的數(shù)組。

// Convert NodeList to Array
let divsArray = [...document.querySelectorAll('div')];

// Convert Arguments to Array
let argsArray = [...arguments];

下面的例子使得一個(gè)類數(shù)組對象符合迭代協(xié)議,并利用spread運(yùn)算符將其轉(zhuǎn)變?yōu)橐粋€(gè)數(shù)組:

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參數(shù)。用三個(gè)點(diǎn)表示。

【02】rest 參數(shù)意味著把剩下的東西包裝成一個(gè)數(shù)組。

【03】用在函數(shù)參數(shù)和解構(gòu)數(shù)組中。

它將一個(gè)逗號分隔的參數(shù)列表轉(zhuǎn)換成一個(gè)數(shù)組。

吃碼小妖:類似打包和解壓的既視感?

如果在函數(shù)形參中使用了rest參數(shù)(打包),那么在函數(shù)中使用spread使用它(解壓),等于原封不動(dòng)的使用實(shí)參了。

【04】當(dāng)三個(gè)點(diǎn)出現(xiàn)在函數(shù)參數(shù)時(shí),它意味著將調(diào)用函數(shù)時(shí)的參數(shù)列表變?yōu)橐粋€(gè)數(shù)組。該參數(shù)名就是這個(gè)數(shù)組。

如果函數(shù)參數(shù)本身就是一個(gè)數(shù)組,那么rest參數(shù)運(yùn)算符等于把函數(shù)形參變?yōu)橐粋€(gè)二維數(shù)組了。

例子:

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】如果是多個(gè)形參,那么rest參數(shù)需要是參數(shù)列表中的最后一個(gè)參數(shù)。寫成逗號分隔的參數(shù)列表。

arguments對象不具有這種選擇性并且始終包含所有的參數(shù)值。

例子:

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】使用不定數(shù)量的函數(shù)參數(shù)。

在ES5中,當(dāng)我們需要處理一個(gè)未知數(shù)量的參數(shù)的函數(shù)時(shí),可以使用arguments變量。

function sum () {
  console.log(arguments)
}

sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//55
圖片.png

計(jì)算這個(gè)參數(shù)總和的一種方法是將其轉(zhuǎn)換成具有 Array.prototype.slice.call(arguments) 的數(shù)組,然后用數(shù)組方法循環(huán)遍歷每個(gè)數(shù)字,如 forEach 或 reduce。

我相信你可以自己實(shí)現(xiàn) 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 參數(shù),可以將所有逗號分隔的參數(shù)直接打包到數(shù)組中。

// 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)
}

【】在數(shù)組解構(gòu)中遇到三個(gè)點(diǎn)。它會將剩余的元素打包變?yōu)橐粋€(gè)數(shù)組。

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 的分?jǐn)?shù),我們可以通過將剩余的分?jǐn)?shù)打包成一個(gè)數(shù)組。

let scores = ['98', '95', '93', '90', '87', '85']
let [first, second, third, ...restOfScores] = scores

console.log(restOfScores) // [90, 97, 95]

用途2:在數(shù)組中插入不定數(shù)量的元素。

例如,.push(item1, ..., itemN)會把元素一個(gè)接一個(gè)的插入數(shù)組:不得不循環(huán)每個(gè)元素將其作為參數(shù)。但這并不總是很方便:有時(shí)需要把一整個(gè)數(shù)組的元素push到目標(biāo)數(shù)組。

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

【】如何更好的把數(shù)組中的元素作為參數(shù)填充到函數(shù)調(diào)用中。

ES5在函數(shù)對象上提供了 .apply()來解決這個(gè)問題。不幸的是這項(xiàng)技術(shù)有3個(gè)問題:

  • 它需要手工的指定函數(shù)調(diào)用的上下文。
  • 它不能使用在構(gòu)造器函數(shù)調(diào)用中。
  • 人們傾向于一個(gè)更短的解決方案。

例子:

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"]

在復(fù)雜情景中的函數(shù)體內(nèi)操作arguments對象是很麻煩的。

為了在filterNumbers()訪問sumOnlyNumbers()的arguments,你不得不創(chuàng)建一個(gè)臨時(shí)變量args。這是因?yàn)閒ilterNumbers()會定義它自己的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運(yùn)算符可以優(yōu)雅的解決這個(gè)問題。它允許你在函數(shù)聲明時(shí)定義一個(gè)rest參數(shù)...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

函數(shù)聲明function sumOnlyNumbers(...args)表明args以數(shù)組的形式接受調(diào)用參數(shù)。


【】箭頭函數(shù)并不定義自己的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運(yùn)算符可以在構(gòu)造器調(diào)用中使用數(shù)組元素作為參數(shù),而這并不能通過直接使用.apply()做到。

讓我們看一個(gè)例子:

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'
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,708評論 0 1
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。 上面代碼檢查函數(shù)l...
    陳老板_閱讀 517評論 0 1
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,716評論 0 5
  • 看了阮老師的《ECMAScript 6 入門》教程,為了之后方便自己隨時(shí)查看,將...操作符相關(guān)的內(nèi)容整理在一起。...
    木A木閱讀 5,431評論 0 8
  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,950評論 0 5

友情鏈接更多精彩內(nèi)容