js?中以?...?為前綴的幾種用法詳解
ES6 開始,js 新增了剩余參數(shù)語法、展開語法等,它們有個(gè)共同之處就是都以 ...
這么個(gè)符號為前綴,好像很多地方都可以用到,但實(shí)際上又不是同一回事,容易讓初學(xué)者暈頭轉(zhuǎn)向。本篇就對目前筆者已知的 3 種關(guān)于 ...
用法的總結(jié)歸納。
用法一:函數(shù)的剩余參數(shù)(Rest parameters)
在定義函數(shù)的時(shí)候,形參當(dāng)中,最后一個(gè)參數(shù)(theArgs
)如果以 ...
作為前綴,那么 theArgs
就會(huì)變?yōu)橐粋€(gè)數(shù)組,調(diào)用該函數(shù)時(shí),如果傳入的實(shí)參數(shù)量大于等于定義函數(shù)時(shí)形參的數(shù)量,比如下面的例 1.1,形參定義了 3 個(gè),卻傳入了 5 個(gè)實(shí)參,那么從 3 開始(包括),之后的實(shí)參都會(huì)被放入到 theArgs
中:
// 例 1.1 function fn(a, b, ...theArgs) { console.log(theArgs) } fn(1, 2, 3, 4, 5) // [ 3, 4, 5 ]
請注意,...theArgs
必須作為最后一個(gè)形參,不然會(huì)報(bào)語法錯(cuò)誤:“SyntaxError: Rest parameter must be last formal parameter”。 除箭頭函數(shù)外,函數(shù)內(nèi)都有個(gè) arguments 可以用來獲取傳遞給函數(shù)的參數(shù)。那么它和剩余參數(shù)有什么區(qū)別呢?
- 剩余參數(shù),比如例 1.1 中的
theArgs
是個(gè)真數(shù)組,可以直接使用數(shù)組的方法,而 arguments 是一個(gè)類數(shù)組(array-like)對象,想要運(yùn)用數(shù)組方法還得轉(zhuǎn)成數(shù)組; - 剩余參數(shù)只包含那些沒有對應(yīng)形參的實(shí)參,比如例 1.1 中的 3、4 和 5,而 arguments 包含了傳給函數(shù)的所有實(shí)參。
- arguments 可以通過 callee 屬性獲取當(dāng)前 arguments 所在的函數(shù)。
其實(shí) arguments 是早期的規(guī)范中為了方便獲取傳入函數(shù)的參數(shù)而存在的,ES6 之后,我們應(yīng)當(dāng)盡量使用剩余參數(shù)這種語法而不是 arguments。
用法二:展開語法(Spread syntax)
展開語法又可以在 3 個(gè)地方使用:
1)調(diào)用函數(shù)時(shí)
剩余參數(shù)是在函數(shù)定義時(shí)形參里使用的,展開語法的用處之一則是在函數(shù)調(diào)用時(shí),傳入的實(shí)參里使用。具體說就是將數(shù)組表達(dá)式或者 string 在語法層面展開作為實(shí)參傳給函數(shù)。比如有如下代碼:
// 例 2.1 const arr = [1, 2, 3] const string = 'Jay' function fn(a, b, c) { console.log(a, b, c) }
fn
接收 3 個(gè)參數(shù),如果我們想把數(shù)組 arr
中的每個(gè)元素傳給 fn
,在 ES6 之前可以利用 apply 實(shí)現(xiàn):
// 例 2.1.1 fn.apply(null, arr) // 1 2 3
有了展開語法,則可以直接將作為參數(shù)的數(shù)組 arr
展開,這樣可以提高代碼的可讀性 :
// 例 2.1.2 fn(...arr) // 1 2 3
展開語法還可以將字符串展開:
// 例 2.1.3 fn(...string) // J a y
2)構(gòu)造數(shù)組時(shí)
通過字面量方式構(gòu)造數(shù)組時(shí),也可以使用展開語法:
// 例 2.2 const arr1 = [1, 2] const arr2 = [3, 4, 5] // 構(gòu)造字面量數(shù)組 const newArr = [...arr1, ...arr2] console.log(newArr) // [ 1, 2, 3, 4, 5 ]
3)構(gòu)造字面量對象時(shí)
除了構(gòu)造數(shù)組,ES2018(ES9) 添加了新的特性使得構(gòu)造對象的時(shí)候也可以運(yùn)用展開語法,被展開的對象表達(dá)式將按 key-value 的方式展開 :
// 例 2.3.1 const obj = { name: 'Jay' } const newObj = { ...obj, age: 40 } console.log(newObj) // { name: 'Jay', age: 40 }
在構(gòu)造對象字面量時(shí),還可以把數(shù)組也放進(jìn)去展開,比如在 MDN 上關(guān)于展開語法的說明中有這么個(gè)例子:
// 例 2.3.2 const obj1 = { foo: 'bar', x: 42 } const obj2 = { foo: 'baz', y: 13 } const merge = (...objects) => ({ ...objects }) const mergedObj = merge(obj1, obj2) console.log(mergedObj) // { '0': { foo: 'bar', x: 42 }, '1': { foo: 'baz', y: 13 } }
乍看上去迷迷糊糊的,可能的難點(diǎn)在于第 4 行代碼的理解,它定義了一個(gè)函數(shù) const merge = (...objects) => ({ ...objects }
, 其中=>
左邊的 ...objects
為函數(shù)的剩余參數(shù)語法,所以 objects
就是一個(gè)由 obj1 和 obj2 這兩個(gè)對象組成的數(shù)組:[ { foo: 'bar', x: 42 }, { foo: 'baz', y: 13 } ]
;=>
右邊的 ...objects
用到的是展開語法,用于構(gòu)造字面量對象,只不過因?yàn)?objects
是個(gè)數(shù)組,所以展開數(shù)組得到的對象的 key 為數(shù)組的下標(biāo),即 { ...objects }
得到的對象為:{ '0': { foo: 'bar', x: 42 }, '1': { foo: 'baz', y: 13 } }
。
注意
在調(diào)用函數(shù)或構(gòu)造數(shù)組時(shí)使用展開語法只能用于可迭代對象,比如不能在構(gòu)造數(shù)組時(shí)把一個(gè)對象放進(jìn)去使用展開語法。
展開語法其實(shí)是一種淺拷貝
在 MDN 文檔還能看到這么一句話:
實(shí)際上, 展開語法和 Object.assign() 行為一致, 執(zhí)行的都是淺拷貝(只遍歷一層)。
也就是說類似下面的例 2.4:
// 例 2.4 const obj = { a: 'a', b: { c: 'd' } } const newObj = { ...obj } newObj.b.c = '我變了' console.log(obj.b.c) // 我變了
我們改變通過展開語法得到的 newObj 的深層屬性 newObj.b.c = '我變了'
時(shí),會(huì)導(dǎo)致 obj.b.c
的值一同被修改。原因可以通過畫內(nèi)存表現(xiàn)圖說明:
const newObj = { ...obj }
生成的 newObj,只是把堆內(nèi)存中 obj 指向的地址為 0x100 這個(gè)對象整個(gè)復(fù)制了一份,生成了地址為 0x300 的新對象(注意這個(gè)新對象里,b 的值是一個(gè)內(nèi)存地址),然后讓 newObj 指向它。如果我們更改了 newObj 的 a 屬性或 b 屬性的值,當(dāng)然不會(huì)影響到 obj 對象,但是如果我們改變的是 newObj.b.c
,就會(huì)找到 0x200 這個(gè)對象并修改,自然會(huì)影響到 obj 對象。
用法三:解構(gòu)數(shù)組時(shí)
在對數(shù)組進(jìn)行解構(gòu)賦值時(shí),我們可以使用剩余模式,將剩余數(shù)組賦值給一個(gè)變量,效果上類似于函數(shù)的剩余參數(shù)。比如下面例 3.1 中的 c
:
// 例 3.1 const arr = [1, 2, 3, 4, 5] const [a, b, ...c] = arr console.log(c) // [ 3, 4, 5 ]
以上就是js 中以 ... 為前綴的幾種用法詳解的詳細(xì)內(nèi)容,更多關(guān)于js ... 前綴用法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS 組件系列之Bootstrap Table的凍結(jié)列功能徹底解決高度問題
這篇文章主要介紹了JS 組件系列之Bootstrap Table的凍結(jié)列功能徹底解決高度問題,需要的朋友可以參考下2017-06-06JS大坑之19位數(shù)的Number型精度丟失問題詳解
這篇文章主要介紹了JS大坑之19位數(shù)的Number型精度丟失問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JS實(shí)現(xiàn)集合的交集、補(bǔ)集、差集、去重運(yùn)算示例【ES5與ES6寫法】
這篇文章主要介紹了JS實(shí)現(xiàn)集合的交集、補(bǔ)集、差集、去重運(yùn)算,結(jié)合實(shí)例形式分析了ES5與ES6語法環(huán)境下的集合常見運(yùn)算操作技巧,需要的朋友可以參考下2019-02-02javascript 冒泡排序 正序和倒序?qū)崿F(xiàn)代碼
javascript 冒泡排序 正序和倒序?qū)崿F(xiàn)代碼,需要的朋友可以參考下。2010-12-12