ES6+ 剩余參數(shù)
1. 前言
上節(jié)我們學習了展開語法,本節(jié)我們學習與之相反的操作 —— 剩余語法(Rest syntax 也可以叫剩余參數(shù))看起來和展開語法完全相同都是使用 ...
的語法糖,不同之處在于剩余參數(shù)用于解構(gòu)數(shù)組和對象。從某種意義上說,剩余語法與展開語法是相反的:展開語法將數(shù)組展開為其中的各個元素,而剩余語法則是將多個元素收集起來成為一個整體。
2. 函數(shù)參數(shù)
在講解剩余參數(shù)前,我們先來看看,剩余參數(shù)在函數(shù)參數(shù)中都解決了哪些問題?為什么會引入剩余參數(shù)的概念?
在 ES5 中,函數(shù)經(jīng)常會傳入不定參數(shù),在傳入不定參數(shù)時,ES5 的給出的解決方案是通過 arguments
對象來獲取函數(shù)調(diào)用時傳遞的參數(shù)。 arguments
對象不是一個數(shù)組,它是一個類數(shù)組對象,所謂類數(shù)組對象,就是指可以通過索引屬性訪問元素并且擁有 length 屬性的對象。
一個簡單的類數(shù)組對象是長這樣的:
var arrLike = {
0: 'name',
1: 'age',
2: 'job',
length: 3
}
而它所對應的數(shù)組應該是這樣子的:
var arr = ['name', 'age', 'job'];
這里我們說類數(shù)組對象與數(shù)組的性質(zhì)相似,是因為類數(shù)組對象在訪問、賦值、獲取長度上的操作與數(shù)組是一致的,具體內(nèi)容可查閱相關的類數(shù)組使用。
在函數(shù)體中定義了 Arguments 對象,其包含函數(shù)的參數(shù)和其它屬性,以 arguments
變量來指代。下面我們看個實例:
function fn() {
console.log(arguments);
}
fn('imooc', 7, 'ES6')
在控制臺中打印出上面的代碼結(jié)果,如下圖所示:在定義函數(shù)的時候沒有給定參數(shù),但是通過 arguments
對象可以拿到傳入的參數(shù)??梢钥吹?arguments
中包含了函數(shù)傳遞的參數(shù)、length 等屬性,length 屬性表示的是實參的長度,即調(diào)用函數(shù)的時候傳入的參數(shù)個數(shù)。這樣我們就對 arguments
對象有了一定的了解。
在 ES5 的開發(fā)模式下,想要使用傳遞的參數(shù),則需要按位置把對應的參數(shù)取出來。盡管 arguments
是一個類數(shù)組且可遍歷的變量,但它終究不是數(shù)組,它不支持數(shù)組方法,因此我們不能調(diào)用 arguments.forEeach (…)
等數(shù)組的方法。需要使用一些特殊的方法轉(zhuǎn)換成數(shù)組使用,如:
function fn() {
var arr = [].slice.call(arguments);
console.log(arr)
}
fn('ES6');
// ["ES6"]
fn('imooc', 7, 'ES6');
// ["imooc", 7, "ES6"]
終于借助 call
方法把 arguments
轉(zhuǎn)化成一個真正的數(shù)組了。但是這樣無疑是一個繁瑣的過程,而且不容易理解。這時 ES6 給出了它的完美解決方案 —— 剩余參數(shù),那剩余參數(shù)是如何在函數(shù)傳參中使用的呢?下面我們來看看實例:
function fn(...args) {
console.log(args)
}
fn('ES6');
// ["ES6"]
fn('imooc', 7, 'ES6');
// ["imooc", 7, "ES6"]
使用方式很簡單在函數(shù)定義時使用 ...
緊接著跟一個收集的參數(shù),這個收集的參數(shù)就是我們所傳入不定參數(shù)的集合 —— 也就是數(shù)組。這樣就很簡單地擺脫了 arguments 的束縛。另外,還可以指定一個默認的參數(shù),如下示例:
function fn(name, ...args) {
console.log(name); // 基礎參數(shù)
console.log(args); // 剩下的參數(shù)組成的數(shù)組
}
fn('ES6');
// 'ES6'
// []
fn('imooc', 7, 'ES6');
// "imooc"
// [7, "ES6"]
上面的代碼中給函數(shù)第一個參數(shù),聲明一個變量 name,剩余的參數(shù)會被 ...
收集成一個數(shù)組,這就是剩余參數(shù)。引入剩余參數(shù)就是為了能替代函數(shù)內(nèi)部的 arguments
,由于 arguments
對象不具備數(shù)組的方法,所以很多時候在使用之前要先轉(zhuǎn)換成一個數(shù)組。而剩余參數(shù)本來就是一個數(shù)組,避免了這多余的一步,使用起來既優(yōu)雅又自然。
2. 解構(gòu)剩余參數(shù)
ES6 允許按照一定模式,從數(shù)組和對象中提取值,并對變量進行賦值,這被稱為解構(gòu)(下節(jié)我們會講到)。 比如如下代碼:
let array = [1, 2, 3]
let [a, b, c] = array;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
再比如如下代碼:
let obj = {a:1, b:2, c:3}
let {a, b, c} = obj;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
上面的兩個例子,就是數(shù)組和對象的解構(gòu)賦值過程,在解構(gòu)賦值時,可以使用剩余操作符。剩余操作符所操作的變量會匹配在解構(gòu)賦值中所有其他變量未匹配到的屬性??慈缦率纠?/p>
let {a, b, ...others } = {a: 1, b: 2, c: 3, d: 4, e: 5}
console.log(a); // 1
console.log(b); // 2
console.log(others); // {c: 3, d: 4, e: 5}
上面的代碼中,a、b 會匹配對象中對應的值,...others
則會收集匹配余下的屬性值,并打包起來構(gòu)造一個新的對象賦值給了 others
。
數(shù)組也可以通過剩余操作符,把剩余的元素打包成一個新的數(shù)組賦值給剩余屬性,代碼如下:
let array = [1, 2, 3, 4, 5];
let [a, b, ...others] = array;
console.log(a); // 1
console.log(b); // 2
console.log(others); // [3,4,5]
在函數(shù)傳參的時候也可以是和解構(gòu)一起使用。如下所示。
function fun(...[a, b, c]) {
return a + b + c;
}
fun('1') // NaN (b 和 c 都是 undefined)
fun(1, 2, 3) // 6
fun(1, 2, 3, 4) // 6 多余的參數(shù)不會被獲取到
上面的代碼中,a、b、c 會去解構(gòu)傳入?yún)?shù),加上有剩余語法的作用,對應的值從數(shù)組中的項解構(gòu)出來,在函數(shù)內(nèi)部直接使用解構(gòu)出來的參數(shù)即可。剩余語法看起來和展開語法完全相同,不同點在于,剩余參數(shù)用于解構(gòu)數(shù)組和對象。
3. 小結(jié)
本節(jié)結(jié)合了 ES5 函數(shù)中的 arguments
對象引入了為什么 ES6 會引入剩余參數(shù)的概念,可以看到剩余參數(shù)所帶來的好處。本節(jié)內(nèi)容可以總結(jié)以下幾點:
- 剩余參數(shù)是為了能替代函數(shù)內(nèi)部的 arguments 而引入的;
- 和展開語法相反,剩余參數(shù)是將多個單個元素聚集起來形成一個單獨的個體的過程。