拓展運(yùn)算符

1.拓展運(yùn)算符是三個(gè)點(diǎn)(...)函似,該運(yùn)算符主要用于函數(shù)調(diào)用锡溯,該運(yùn)算符將一個(gè)數(shù)組菇用,變?yōu)閰?shù)序列
···javascript
function push(array, ...items) {
array.push(...items);
}

function add(x, y) {
return x + y;
}

const numbers = [4, 38];
add(...numbers) // 42
···
他替代了apply方法
由于擴(kuò)展運(yùn)算符可以展開數(shù)組塞弊,所以不再需要apply方法缀匕,將數(shù)組轉(zhuǎn)為函數(shù)的參數(shù)了。

擴(kuò)展運(yùn)算符的作用
(1)復(fù)制數(shù)組
數(shù)組是復(fù)合的數(shù)據(jù)類型释树,直接復(fù)制的話肠槽,只是復(fù)制了指向底層數(shù)據(jù)結(jié)構(gòu)的指針,而不是克隆一個(gè)全新的數(shù)組躏哩。

const a1 = [1, 2];
const a2 = a1;

a2[0] = 2;
a1 // [2, 2]

上面代碼中署浩,a2并不是a1的克隆揉燃,而是指向同一份數(shù)據(jù)的另一個(gè)指針扫尺。修改a2,會(huì)直接導(dǎo)致a1的變化炊汤。
ES5 只能用變通方法來復(fù)制數(shù)組正驻。

const a1 = [1, 2];
const a2 = a1.concat();

a2[0] = 2;
a1 // [1, 2]
···
上面代碼中,a1會(huì)返回原數(shù)組的克隆抢腐,再修改a2就不會(huì)對(duì)a1產(chǎn)生影響姑曙。

擴(kuò)展運(yùn)算符提供了復(fù)制數(shù)組的簡便寫法。
```javascript
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;

上面代碼中迈倍,a1會(huì)返回原數(shù)組的克隆伤靠,再修改a2就不會(huì)對(duì)a1產(chǎn)生影響。

擴(kuò)展運(yùn)算符提供了復(fù)制數(shù)組的簡便寫法啼染。

const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;

上面的兩種寫法宴合,a2都是a1的克隆焕梅。

(2)合并數(shù)組

擴(kuò)展運(yùn)算符提供了數(shù)組合并的新寫法。

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并數(shù)組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并數(shù)組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

不過卦洽,這兩種方法都是淺拷貝贞言,使用的時(shí)候需要注意。

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true

上面代碼中阀蒂,a3和a4是用兩種不同方法合并而成的新數(shù)組该窗,但是它們的成員都是對(duì)原數(shù)組成員的引用,這就是淺拷貝蚤霞。如果修改了引用指向的值酗失,會(huì)同步反映到新數(shù)組。

(3)與解構(gòu)賦值結(jié)合

擴(kuò)展運(yùn)算符可以與解構(gòu)賦值結(jié)合起來昧绣,用于生成數(shù)組级零。

// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

如果將擴(kuò)展運(yùn)算符用于數(shù)組賦值,只能放在參數(shù)的最后一位滞乙,否則會(huì)報(bào)錯(cuò)奏纪。

const [...butLast, last] = [1, 2, 3, 4, 5];
// 報(bào)錯(cuò)

const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 報(bào)錯(cuò)

(4)字符串

擴(kuò)展運(yùn)算符還可以將字符串轉(zhuǎn)為真正的數(shù)組。

[...'hello']
// [ "h", "e", "l", "l", "o" ]

上面的寫法斩启,有一個(gè)重要的好處序调,那就是能夠正確識(shí)別四個(gè)字節(jié)的 Unicode 字符。

'x\uD83D\uDE80y'.length // 4
[...'x\uD83D\uDE80y'].length // 3

上面代碼的第一種寫法兔簇,JavaScript 會(huì)將四個(gè)字節(jié)的 Unicode 字符发绢,識(shí)別為 2 個(gè)字符,采用擴(kuò)展運(yùn)算符就沒有這個(gè)問題垄琐。因此边酒,正確返回字符串長度的函數(shù),可以像下面這樣寫狸窘。

function length(str) {
  return [...str].length;
}

length('x\uD83D\uDE80y') // 3

凡是涉及到操作四個(gè)字節(jié)的 Unicode 字符的函數(shù)墩朦,都有這個(gè)問題。因此翻擒,最好都用擴(kuò)展運(yùn)算符改寫氓涣。

let str = 'x\uD83D\uDE80y';

str.split('').reverse().join('')
// 'y\uDE80\uD83Dx'

[...str].reverse().join('')
// 'y\uD83D\uDE80x'

上面代碼中,如果不用擴(kuò)展運(yùn)算符陋气,字符串的reverse操作就不正確劳吠。

(5)實(shí)現(xiàn)了 Iterator 接口的對(duì)象

任何定義了遍歷器(Iterator)接口的對(duì)象(參閱 Iterator 一章),都可以用擴(kuò)展運(yùn)算符轉(zhuǎn)為真正的數(shù)組巩趁。

let nodeList = document.querySelectorAll('div');
let array = [...nodeList];

上面代碼中痒玩,querySelectorAll方法返回的是一個(gè)NodeList對(duì)象。它不是數(shù)組,而是一個(gè)類似數(shù)組的對(duì)象蠢古。這時(shí)燃观,擴(kuò)展運(yùn)算符可以將其轉(zhuǎn)為真正的數(shù)組,原因就在于NodeList對(duì)象實(shí)現(xiàn)了 Iterator 便瑟。

Number.prototype[Symbol.iterator] = function*() {
  let i = 0;
  let num = this.valueOf();
  while (i < num) {
    yield i++;
  }
}

console.log([...5]) // [0, 1, 2, 3, 4]

上面代碼中缆毁,先定義了Number對(duì)象的遍歷器接口,擴(kuò)展運(yùn)算符將5自動(dòng)轉(zhuǎn)成Number實(shí)例以后到涂,就會(huì)調(diào)用這個(gè)接口脊框,就會(huì)返回自定義的結(jié)果。

對(duì)于那些沒有部署 Iterator 接口的類似數(shù)組的對(duì)象践啄,擴(kuò)展運(yùn)算符就無法將其轉(zhuǎn)為真正的數(shù)組浇雹。

let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};

// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];

上面代碼中,arrayLike是一個(gè)類似數(shù)組的對(duì)象屿讽,但是沒有部署 Iterator 接口昭灵,擴(kuò)展運(yùn)算符就會(huì)報(bào)錯(cuò)。這時(shí)伐谈,可以改為使用Array.from方法將arrayLike轉(zhuǎn)為真正的數(shù)組烂完。

(6)Map 和 Set 結(jié)構(gòu),Generator 函數(shù)

擴(kuò)展運(yùn)算符內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的 Iterator 接口诵棵,因此只要具有 Iterator 接口的對(duì)象抠蚣,都可以使用擴(kuò)展運(yùn)算符,比如 Map 結(jié)構(gòu)履澳。

let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let arr = [...map.keys()]; // [1, 2, 3]

Generator 函數(shù)運(yùn)行后嘶窄,返回一個(gè)遍歷器對(duì)象,因此也可以使用擴(kuò)展運(yùn)算符距贷。

const go = function*(){
  yield 1;
  yield 2;
  yield 3;
};

[...go()] // [1, 2, 3]

上面代碼中柄冲,變量go是一個(gè) Generator 函數(shù),執(zhí)行后返回的是一個(gè)遍歷器對(duì)象忠蝗,對(duì)這個(gè)遍歷器對(duì)象執(zhí)行擴(kuò)展運(yùn)算符现横,就會(huì)將內(nèi)部遍歷得到的值,轉(zhuǎn)為一個(gè)數(shù)組什湘。

如果對(duì)沒有 Iterator 接口的對(duì)象长赞,使用擴(kuò)展運(yùn)算符晦攒,將會(huì)報(bào)錯(cuò)闽撤。

const obj = {a: 1, b: 2};
let arr = [...obj]; // TypeError: Cannot spread non-iterable object
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市脯颜,隨后出現(xiàn)的幾起案子哟旗,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闸餐,死亡現(xiàn)場(chǎng)離奇詭異饱亮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舍沙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門近上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拂铡,你說我怎么就攤上這事壹无。” “怎么了感帅?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵斗锭,是天一觀的道長。 經(jīng)常有香客問我失球,道長岖是,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任实苞,我火速辦了婚禮豺撑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘黔牵。我一直安慰自己前硫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布荧止。 她就那樣靜靜地躺著屹电,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跃巡。 梳的紋絲不亂的頭發(fā)上危号,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音素邪,去河邊找鬼外莲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛兔朦,可吹牛的內(nèi)容都是我干的偷线。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼沽甥,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼声邦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起摆舟,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤亥曹,失蹤者是張志新(化名)和其女友劉穎邓了,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媳瞪,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡骗炉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛇受。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片句葵。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖兢仰,靈堂內(nèi)的尸體忽然破棺而出笼呆,到底是詐尸還是另有隱情,我是刑警寧澤旨别,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布诗赌,位于F島的核電站,受9級(jí)特大地震影響秸弛,放射性物質(zhì)發(fā)生泄漏铭若。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一递览、第九天 我趴在偏房一處隱蔽的房頂上張望叼屠。 院中可真熱鬧,春花似錦绞铃、人聲如沸镜雨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荚坞。三九已至,卻和暖如春菲盾,著一層夾襖步出監(jiān)牢的瞬間颓影,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工懒鉴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诡挂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓临谱,卻偏偏與公主長得像璃俗,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悉默,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348