es6的三個(gè)點(diǎn)不是函數(shù),而是一種運(yùn)算符。三個(gè)點(diǎn)“…”指的是“擴(kuò)展運(yùn)算符”,可將可迭代對象展開到其單獨(dú)的元素中;所謂的可迭代對象就是任何能用for of循環(huán)進(jìn)行遍歷的對象,例如數(shù)組、字符串、Map、Set、DOM節(jié)點(diǎn)等。
前端(vue)入門到精通課程:進(jìn)入學(xué)習(xí)
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調(diào)試工具:點(diǎn)擊使用
本教程操作環(huán)境:windows7系統(tǒng)、javascript1.8.5版、Dell G3電腦。
擴(kuò)展操作符 … 是ES6中引入的,將可迭代對象展開到其單獨(dú)的元素中,所謂的可迭代對象就是任何能用for of循環(huán)進(jìn)行遍歷的對象,例如:數(shù)組(數(shù)組常用方法)、字符串、Map (悟透Map)、Set (Set 如何使用?)、DOM節(jié)點(diǎn)等。
數(shù)組擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符(spread)是三個(gè)點(diǎn)(...
)。它好比 rest 參數(shù)的逆運(yùn)算,將一個(gè)數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列。擴(kuò)展運(yùn)算符與正常的函數(shù)參數(shù)可以結(jié)合使用,后面也可以放置表達(dá)式,但如果后面是一個(gè)空數(shù)組,則不產(chǎn)生任何效果。
let arr = []; arr.push(...[1,2,3,4,5]); console.log(arr); //[1,2,3,4,5] console.log(1, ...[2, 3, 4], 5) //1 2 3 4 5 console.log(...(1 > 0 ? ['a'] : [])); //a console.log([...[], 1]); //[1]
意義
替代函數(shù)的apply方法
由于擴(kuò)展運(yùn)算符可以展開數(shù)組,所以不再需要apply
方法,將數(shù)組轉(zhuǎn)為函數(shù)的參數(shù)了。
// ES5 的寫法 Math.max.apply(null, [14, 3, 77]) // ES6 的寫法 Math.max(...[14, 3, 77])
應(yīng)用
-
復(fù)制數(shù)組
// ES5 的寫法 const a1 = [1, 2]; const a2 = a1.concat(); // ES6 的寫法 const a1 = [1, 2]; const a2 = [...a1]; //或 const [...a2] = a1;
登錄后復(fù)制 -
合并數(shù)組
// ES5 的寫法 [1, 2].concat(more); arr1.concat(arr2, arr3); // ES6 的寫法 [1, 2, ...more]; [...arr1, ...arr2, ...arr3]
登錄后復(fù)制 -
與解構(gòu)賦值結(jié)合
// ES5 的寫法 a = list[0], rest = list.slice(1) // ES6 的寫法 [a, ...rest] = list
登錄后復(fù)制注意:如果將擴(kuò)展運(yùn)算符用于數(shù)組賦值,只能放在參數(shù)的最后一位,否則會報(bào)錯。
-
轉(zhuǎn)換字符串
擴(kuò)展運(yùn)算符還可以將字符串轉(zhuǎn)為真正的數(shù)組,并且能夠正確識別四個(gè)字節(jié)的 Unicode 字符。
'xuD83DuDE80y'.length // 4 [...'xuD83DuDE80y'].length // 3 let str = 'xuD83DuDE80y'; str.split('').reverse().join('') // 'yuDE80uD83Dx' [...str].reverse().join('') // 'yuD83DuDE80x'
登錄后復(fù)制 -
實(shí)現(xiàn)Iterator接口的對象
任何 Iterator 接口的對象(參閱 Iterator 一章),都可以用擴(kuò)展運(yùn)算符轉(zhuǎn)為真正的數(shù)組。
-
Map和Set結(jié)構(gòu)、Generator函數(shù)
- 擴(kuò)展運(yùn)算符內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的 Iterator 接口,因此只要具有 Iterator 接口的對象,都可以使用擴(kuò)展運(yùn)算符,比如 Map 結(jié)構(gòu)。
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); let arr = [...map.keys()]; // [1, 2, 3]
登錄后復(fù)制- Generator 函數(shù)運(yùn)行后,返回一個(gè)遍歷器對象,因此也可以使用擴(kuò)展運(yùn)算符。
const go = function*(){ yield 1; yield 2; yield 3; }; [...go()] // [1, 2, 3]
登錄后復(fù)制- 如果對沒有 Iterator 接口的對象,使用擴(kuò)展運(yùn)算符,將會報(bào)錯。
對象的擴(kuò)展運(yùn)算符
概念
對象的解構(gòu)賦值用于從一個(gè)對象取值,相當(dāng)于將目標(biāo)對象自身的所有可遍歷的(enumerable)、但尚未被讀取的屬性,分配到指定的對象上面。所有的鍵和它們的值,都會拷貝到新對象上面。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
注意:
-
由于解構(gòu)賦值要求等號右邊是一個(gè)對象,所以如果等號右邊是
undefined
或null
,就會報(bào)錯,因?yàn)樗鼈儫o法轉(zhuǎn)為對象。 -
解構(gòu)賦值必須是最后一個(gè)參數(shù),否則會報(bào)錯。
-
解構(gòu)賦值的拷貝是淺拷貝,即如果一個(gè)鍵的值是復(fù)合類型的值(數(shù)組、對象、函數(shù))、那么解構(gòu)賦值拷貝的是這個(gè)值的引用,而不是這個(gè)值的副本。
let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
登錄后復(fù)制 -
擴(kuò)展運(yùn)算符的解構(gòu)賦值,不能復(fù)制繼承自原型對象的屬性。
let o1 = { a: 1 }; let o2 = { b: 2 }; o2.__proto__ = o1; let { ...o3 } = o2; o3 // { b: 2 } o3.a // undefined const o = Object.create({ x: 1, y: 2 }); o.z = 3; let { x, ...newObj } = o; let { y, z } = newObj; x // 1 y // undefined z // 3 let { x, ...{ y, z } } = o; // SyntaxError: ... must be followed by an identifier in declaration contexts
登錄后復(fù)制
應(yīng)用
-
擴(kuò)展某個(gè)函數(shù)的參數(shù),引入其他操作。
function baseFunction({ a, b }) { // ... } function wrapperFunction({ x, y, ...restConfig }) { // 使用 x 和 y 參數(shù)進(jìn)行操作 // 其余參數(shù)傳給原始函數(shù) return baseFunction(restConfig); }
-
取出參數(shù)對象的所有可遍歷屬性,拷貝到當(dāng)前對象之中。
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 } let aClone = { ...a }; // 等同于 let aClone = Object.assign({}, a); //上面的例子只是拷貝了對象實(shí)例的屬性,如果想完整克隆一個(gè)對象,還拷貝對象原型的屬性,可以采用下面的寫法。 // 寫法一 const clone1 = Object.assign( Object.create(Object.getPrototypeOf(obj)), obj ); // 寫法二 const clone2 = Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) )
-
合并兩個(gè)對象。
let ab = { ...a, ...b }; // 等同于 let ab = Object.assign({}, a, b); //如果用戶自定義的屬性,放在擴(kuò)展運(yùn)算符后面,則擴(kuò)展運(yùn)算符內(nèi)部的同名屬性會被覆蓋掉。 let aWithOverrides = { ...a, x: 1, y: 2 }; // 等同于 let aWithOverrides = { ...a, ...{ x: 1, y: 2 } }; // 等同于 let x = 1, y = 2, aWithOverrides = { ...a, x, y }; // 等同于 let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
登錄后復(fù)制 -
修改現(xiàn)有對象部分的屬性。
let newVersion = { ...previousVersion, name: 'New Name' // Override the name property };
登錄后復(fù)制
其他
- 如果把自定義屬性放在擴(kuò)展運(yùn)算符前面,就變成了設(shè)置新對象的默認(rèn)屬性值。
- 與數(shù)組的擴(kuò)展運(yùn)算符一樣,對象的擴(kuò)展運(yùn)算符后面可以跟表達(dá)式。
- 如果擴(kuò)展運(yùn)算符后面是一個(gè)空對象,則沒有任何效果。
- 如果擴(kuò)展運(yùn)算符的參數(shù)是
null
或undefined
,這兩個(gè)值會被忽略,不會報(bào)錯。 -
擴(kuò)展運(yùn)算符的參數(shù)對象之中,如果有取值函數(shù)
get
,這個(gè)函數(shù)是會執(zhí)行的。
【