擴展運算符(Spread Operator)和剩餘參數(Rest Parameter)的寫法相同,都是在變量或字面量以前加三個點(...),而且只能用於包含Symbol.iterator屬性的可迭代對象(iterable)。雖然二者之間有諸多相似,但它們的功能和應用場景卻徹底不一樣。擴展運算符能把總體展開成個體,經常使用於函數調用、數組或字符串處理等;而剩餘參數正好相反,把個體合併成總體,經常使用於函數聲明、解構參數等。此處的總體多是數組、字符串或類數組對象等,個體多是字符、數組的元素或函數的參數等。html
擴展運算符的用途簡單歸納,能夠分爲如下三種。數組
(1)替代函數的apply()方法。app
(2)簡化函數調用時傳遞實參的方式。dom
(3)處理數組和字符串。函數
1)apply()this
函數的apply()方法可以間接調用其它對象的方法,每每能收穫奇效,例如用Math對象的min()方法獲取數組中的最小值,min()方法原本只接收一組參數,利用apply()方法後就能直接傳遞一個數組,以下所示。spa
let arr = [1, 0, 2], min; min = Math.min(1, 0, 2); //一組參數的調用方式 min = Math.min.apply(undefined, arr); //利用apply()間接調用
雖然apply()方法很便捷,但每次都必須設置this的指向(即定義第一個參數),而且迂迴的寫法可能會爲理解代碼意圖設置障礙。而使用擴展運算符後,既能以簡單的語法形式完成相同的功能,還能更清晰的代表代碼的意圖。下面用擴展運算符查找數組中的最小值。rest
min = Math.min(...arr); console.log(min); //0
2)傳參code
函數在被調用時,實參一般都是以逗號分隔的序列形式傳遞到函數體內。若是實參的值被保存在數組中,那麼就要一個一個的讀取數組中指定位置的元素,例如建立一個日期對象(調用它的構造函數),把年月日的信息保存在數組中,以下代碼所示。註釋中的日期並非默認的顯示格式,只是爲了更容易閱讀而這麼寫的。htm
let date = [2018, 6, 9]; new Date(date[0], date[1], date[2]); //2018-7-6
換成擴展運算符的寫法後,實參的傳遞就變得很是的簡潔,以下所示。
new Date(...date); //2018-7-6
不只如此,在調用函數的時候,還可使用多個擴展運算符,並能和普通的實參混合使用,以下所示。
let time = [10, 28]; new Date(...date, ...time, 45); //2018-7-6 10:28:45
3)數組和字符串
在擴展運算符出現以前,要執行數組的複製、合併等操做,須要調用數組的slice()、concat()、unshift()等方法。這些方法究竟是單獨調用仍是組合調用,由實際狀況而定。下面是一個數組複製與合併的簡單示例。
let arr1 = [1, 2, 3], arr2, arr3; arr2 = arr1.slice(); //複製數組 arr3 = arr2.concat(arr1); //合併數組 console.log(arr1); //[1, 2, 3] console.log(arr2); //[1, 2, 3] console.log(arr3); //[1, 2, 3, 1, 2, 3]
接下來用擴展運算符來完成一樣的功能,以下代碼所示。
arr2 = [...arr1]; //複製數組 arr3 = [...arr1, ...arr2]; //合併數組
在實際項目中,確定會碰到各式各樣的數組操做,合理利用擴展運算符,不但能夠節省大量的代碼,還能提高代碼的可讀性。
擴展運算符不只能處理數組,還能處理字符串。在JavaScript中,字符串的行爲相似於數組,但它不能直接調用數組的方法,須要先執行本身的split()方法轉換成數組。而使用擴展運算符後,就能省去這步操做,具體以下所示,注意,包裹的方括號不能省略。
let str = "strick"; str.split(""); //["s", "t", "r", "i", "c", "k"] [...str]; //["s", "t", "r", "i", "c", "k"]
在JavaScript的函數中,聲明時定義的形參個數能夠和傳入的實參個數不一樣。當實參個數大於形參個數時,ES6新增的剩餘參數能把沒有對應形參的實參收集到一個數組中。下面是一個簡單的示例。
function func(name, ...args) { console.log(name); console.log(args[0]); } func("strick"); //首先輸出"strick",而後輸出undefined func("freedom", 29); //首先輸出"freedom",而後輸出29
第一次調用func()函數只傳入了一個實參,對應的形參就是name。第二次調用func()函數傳入了兩個實參,第一個有對應的形參,而第二個並無對應的形參。此時,該實參就會被放到數組args(就是剩餘參數)中,變爲該數組的一個元素,在函數體內就能經過數組的索引讀取該實參。有一點要注意,剩餘參數不會影響函數的length屬性,該屬性的值表示形參個數。以上面的func()函數爲例,... args並非一個形參,所以,func()函數的length屬性值爲1。
console.log(func.length); //1
1)解構
剩餘參數能夠被解構(將在第3篇中講解),這意味着剩餘參數中的元素能夠被賦給函數體中的同名變量,以下所示。
function destructuring (name, ...[age]) { console.log(name); console.log(age); } destructuring ("jane", 28); //首先輸出"jane",而後輸出28
引入剩餘參數就是爲了能替代函數內部的arguments,它是一個類數組對象,管理着實參列表,該列表包含了傳入到函數內的全部實參。因爲arguments對象不具有數組的方法,因此不少時候在使用以前要先轉換成一個數組。而剩餘參數原本就是一個數組,避免了這多餘的一步,使用起來既優雅又天然。
2)兩點限制
剩餘參數有兩點限制,在使用時須要引發注意。第一點是在函數中聲明時必須放在最後,下面是一種錯誤的寫法。
function restrict1(...args, name) { //拋出語法錯誤 }
第二點是不能在對象字面量的setter方法中聲明,由於該方法只接收一個參數,而剩餘參數不會限制參數的數量。注意,setter方法在定義時會用set替代function關鍵字,下面是一個會拋出語法錯誤的例子。
var obj = { set age(...value) { this._age = value; } };