... 運(yùn)算符,是 ES6 里一個(gè)新引入的運(yùn)算法,也叫 展開(kāi)/收集 運(yùn)算符,我們每天都要和它打交道。 這篇文章,我就帶你系統(tǒng)的回顧下這個(gè)運(yùn)算符,介紹一些基礎(chǔ)和進(jìn)階的用法。Spread syntax allows an iterable, such as an array expression or string, to be expanded in places where 0 or more arguments or elements are expected or an object expression to be expanded in places where 0 or more key-value pairs (for object literals) are expected. 簡(jiǎn)而言之就是,... 運(yùn)算符可以展開(kāi)一個(gè)可迭代對(duì)象重的所有項(xiàng)。 可迭代的對(duì)象一般是指可以被循環(huán)的,包括:string, array, set 等等。下面我們來(lái)看幾個(gè)基礎(chǔ)的例子來(lái)加深理解。基礎(chǔ)用法
基礎(chǔ)用法 1: 展開(kāi)const a = [2, 3, 4] const b = [1, ...a, 5]
b; // [1, 2, 3, 4, 5]
基礎(chǔ)用法 2: 收集function foo(a, b, ...c) { console.log(a, b, c) }
foo(1, 2, 3, 4, 5); // 1, 2, [3, 4, 5] 如果沒(méi)有命名參數(shù)的話(huà),... 就會(huì)收集所有的參數(shù):function foo(...args) { console.log(args) }
foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5] 關(guān)于這個(gè)收集的用法,官方描述:“A function’s last parameter can be prefixed with ... which will cause all remaining (user supplied) arguments to be placed within a 'standard' javascript array. Only the last parameter can be a rest parameter.” 這個(gè)運(yùn)算符一定是在最后一個(gè)參數(shù)的位置,也很好理解,就是“收集前面剩下的參數(shù)”。
Remember that the rest parameter must be the last parameter, or an error will occur. 如果不在最后一位,會(huì)報(bào)錯(cuò)。 不得不感嘆,這個(gè)運(yùn)算符設(shè)計(jì)的真的是妙,可展開(kāi),可收集,收放自如,當(dāng)真好用。基礎(chǔ)用法 3: 把 類(lèi)數(shù)組 轉(zhuǎn)換為 數(shù)組類(lèi)數(shù)組和數(shù)組非常接近,都可以擁有一系列元素,也有l(wèi)ength 屬性,最大的不同是:類(lèi)數(shù)組不具備數(shù)組的一系列方法。const nodeList = document.getElementsByClassName('test'); const array = [...nodeList];
console.log(nodeList); //Result: HTMLCollection [ div.test, div.test ] console.log(array); //Result: Array [ div.test, div.test ] 使用 ... 就可以實(shí)現(xiàn)類(lèi)數(shù)組到數(shù)組的轉(zhuǎn)換,轉(zhuǎn)換之后,就可以使用數(shù)組的各種方法了。你還記得在這個(gè)操作符出來(lái)之前是如何轉(zhuǎn)換的嗎?這個(gè)問(wèn)題還是頭條的一個(gè)前端面試題。// ES5 時(shí)代 function bar() { var args = Array.prototype.slice.call(arguments);
// 調(diào)用push 加幾個(gè)元素 args.push(1, 2, 3);
// 把a(bǔ)rgs 作為參數(shù)傳遞給foo foo.apply(null, args)
}
// ES6 時(shí)代
function foo(...args) { // 搜集參數(shù)到 args
args.push(4, 5, 6)
console.log(...args) // 展開(kāi)args
}
bar(0); // 0 1 2 3 4 5 6
基礎(chǔ)用法 4: 增加元素或?qū)傩?/h3>1: 為數(shù)組新增成員const pokemon = ['KK', 'Peter']; const charmander = '鄭伊健';
const pokedex = [...pokemon, charmander];
console.log(pokedex);
//Result: [ 'KK', 'Peter', '鄭伊健' ]
2: 為對(duì)象新增屬性const basicSquirtle = { name: 'Squirtle', type: 'Water' }; const fullSquirtle = { ...basicSquirtle, species: 'Tiny Turtle', evolution: 'Wartortle' };
console.log(fullSquirtle);
//Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle', evolution: 'Wartortle' } 基礎(chǔ)用法 5: 合并數(shù)組/對(duì)象
合并數(shù)組:const pokemon = ['Squirtle', 'Bulbasur', 'Charmander']; const morePokemon = ['Totodile', 'Chikorita', 'Cyndaquil'];
const pokedex = [...pokemon, ...morePokemon];
console.log(pokedex); //Result: [ 'Squirtle', 'Bulbasur', 'Charmander', 'Totodile', 'Chikorita', 'Cyndaquil' ]
// 對(duì)象數(shù)組也一樣: const pokemon = [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' } ]; const morePokemon = [{ name: 'Charmander', type: 'Fire' }];
const pokedex = [...pokemon, ...morePokemon];
console.log(pokedex);
//Result: [ { name: 'Squirtle', type: 'Water' }, { name: 'Bulbasur', type: 'Plant' }, { name: 'Charmander', type: 'Fire' } ] const baseSquirtle = { name: 'Squirtle', type: 'Water' };
const squirtleDetails = { species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' };
const squirtle = { ...baseSquirtle, ...squirtleDetails }; console.log(squirtle); //Result: { name: 'Squirtle', type: 'Water', species: 'Tiny Turtle Pokemon', evolution: 'Wartortle' }
1. 復(fù)制具有嵌套結(jié)構(gòu)的數(shù)據(jù)/對(duì)象
const pokemon = { name: 'Squirtle', type: 'Water', abilities: ['Torrent', 'Rain Dish'] };
const squirtleClone = { ...pokemon };
pokemon.name = 'Charmander'; pokemon.abilities.push('Surf');
console.log(squirtleClone);
//Result: { name: 'Squirtle', type: 'Water', abilities: [ 'Torrent', 'Rain Dish', 'Surf' ] } 當(dāng)我們修改原對(duì)象的 name 屬性時(shí),我們的克隆對(duì)象的 name 屬性沒(méi)有受影響,這是符合我們預(yù)期的。但是當(dāng)修改原對(duì)象的 abilities 屬性時(shí),我們的克隆對(duì)象也被修改了。原因也很簡(jiǎn)單,因?yàn)閺?fù)制過(guò)來(lái)的 abilities 是一個(gè)引用類(lèi)型,原數(shù)據(jù)改了,用到他的地方也會(huì)跟著改。知道原因,再解決就很簡(jiǎn)單了,兩種方式:1、復(fù)制引用類(lèi)型的數(shù)據(jù)const pokemon = { name: 'Squirtle', type: 'Water', abilities: ['Torrent', 'Rain Dish'] };
const squirtleClone = { ...pokemon, abilities: [...pokemon.abilities] };
pokemon.name = 'Charmander'; pokemon.abilities.push('Surf');
console.log(squirtleClone);
//Result: { name: 'Squirtle', type: 'Water', abilities: [ 'Torrent', 'Rain Dish' ] }
2、深克隆2. 增加條件屬性const pokemon = { name: 'Squirtle', type: 'Water' };
const abilities = ['Torrent', 'Rain dish']; const fullPokemon = abilities ? { ...pokemon, abilities } : pokemon;
console.log(fullPokemon);
3. 短路const pokemon = { name: 'Squirtle', type: 'Water' };
const abilities = ['Torrent', 'Rain dish']; const fullPokemon = { ...pokemon, ...(abilities && { abilities }) };
console.log(fullPokemon); 如果 abilities 為 true,就相當(dāng)于是const fullPokemon = { ...pokemon, ...{ abilities } }
4. 默認(rèn)結(jié)構(gòu)和添加默認(rèn)屬性
默認(rèn)結(jié)構(gòu):我們知道,當(dāng)結(jié)構(gòu)一個(gè)對(duì)象的時(shí)候,如果這個(gè)對(duì)象里沒(méi)有某個(gè)屬性,解出來(lái)是undefined , 我們可以添加默認(rèn)值來(lái)解決:const pokemon = { id: 1, name: 'Squirtle' };
const { type, name } = pokemon; console.log(name); //Result: Squirtle console.log(type); //Result: undefined
//Assigning default value to the type variable const { type = 'Water', name } = pokemon; console.log(type); //Result: Water
添加默認(rèn)屬性有時(shí)候從我們會(huì)遇到這樣的情況,一個(gè)對(duì)象,大部分屬性是相似的,只有小部分是不不同的,這時(shí)候我們就可以設(shè)置一個(gè)基礎(chǔ)對(duì)象,具備基礎(chǔ)屬性,其他的對(duì)象可以通過(guò)擴(kuò)展這個(gè)對(duì)象來(lái)得到。const pokemon = { name: 'Squirtle', type: 'Water' };
// 給abilities默認(rèn)賦值 const { abilities = [], ...rest } = pokemon;
const fullSquirtle = { ...rest, abilities };
console.log(rest); //Result: { name: 'Squirtle', type: 'Water' } console.log({ fullSquirtle }); //Result: { name: 'Squirtle', type: 'Water', abilities: [] } 這里就是通過(guò)展開(kāi) rest , 合并 abilities 得到完全體的數(shù)據(jù)。 如果有批量的數(shù)據(jù)需要處理,這種方法也非常方便:const pokemon = [ { name: 'Charmander', type: 'Fire' }, { name: 'Squirtle', type: 'Water', abilities: ['Torrent', 'Rain Dish'] }, { name: 'Bulbasur', type: 'Plant' } ];
function setDefaultAbilities(object) { const { abilities = [], ...rest } = object; return { ...rest, abilities }; }
// Applying the setDefaultAbilities function to all the pokemon in the array: const normalizedPokemon = pokemon.map(pokemon => setDefaultAbilities(pokemon));
console.log(normalizedPokemon);
//Result: [ { name: 'Charmander', type: 'Fire', abilities: [] }, { name: 'Squirtle', type: 'Water', abilities: [ 'Torrent', 'Rain Dish' ] }, { name: 'Bulbasur', type: 'Plant', abilities: [] } ] 這樣迭代一遍,所有的對(duì)象就都具備 abilities 屬性了。... 運(yùn)算符非常靈活,收放自如,非常強(qiáng)大,希望我們都能很好的掌握這個(gè)工具。
|