深入理解ES6 改進(jìn)的數(shù)組功能

Set集合與Map集合
迭代器(Iterator)和生成器(Generator)
改進(jìn)的數(shù)組功能

改進(jìn)的數(shù)組功能

1.創(chuàng)建數(shù)組

ES6之前,創(chuàng)建數(shù)組的方式主要有兩種,一種是調(diào)用Array構(gòu)造函數(shù),另一種是用數(shù)組字面量語(yǔ)法,這兩種方法均需列舉數(shù)組中的元素,功能非常受限。如果想將一個(gè)類數(shù)組對(duì)象(具有數(shù)值型索引和length屬性的對(duì)象)轉(zhuǎn)換為數(shù)組,可選的方法也十分有限,經(jīng)常需要編寫(xiě)額外的代碼。為了進(jìn)一步簡(jiǎn)化JS數(shù)組的創(chuàng)建過(guò)程,ES6新增了Array.of()Array.from()兩個(gè)方法

//使用new Array() 創(chuàng)建數(shù)組
var arr1 = new Array();     // 空數(shù)組
var arr2 = new Array('蘋(píng)果', '橘子', '香蕉', '桃子');      //含有4個(gè)元素
//使用字面量來(lái)創(chuàng)建數(shù)組
var arr1 = [];      //空數(shù)組
var arr2 = ['蘋(píng)果', '橘子', '香蕉', '桃子'];     //含有4個(gè)元素

[Array.of()]

ES6之所以向JS添加新的創(chuàng)建方法,是要幫助開(kāi)發(fā)者們規(guī)避通過(guò)Array構(gòu)造函數(shù)創(chuàng)建數(shù)組時(shí)的怪異行為

let items =new Array(2);
console.log(items.length); // 2
console.log(items[0]);// undefined
console.log(items[1]);// undefined
items =new Array("2");
console.log(items.length); // 1
console.log(items[0]);// "2"
items =new Array(1, 2);
console.log(items.length); // 2
console.log(items[0]);// 1
console.log(items[1]);// 2
items =new Array(3, "2");
console.log(items.length); // 2
console.log(items[0]);// 3
console.log(items[1]);// "2"
  • 如果給Array構(gòu)造函數(shù)傳入一個(gè)數(shù)值型的值,那么數(shù)組的length屬性會(huì)被設(shè)為該值。如果傳入多個(gè)值,此時(shí)無(wú)論這些值是不是數(shù)值型的,都會(huì)變?yōu)閿?shù)組的元素。這個(gè)特性令人感到困惑,不可能總是注意傳入數(shù)據(jù)的類型,所以存在一定的風(fēng)險(xiǎn)
  • ES6通過(guò)引入Array.of()方法來(lái)解決這個(gè)問(wèn)題。Array.of()Array構(gòu)造函數(shù)的工作機(jī)制類似,只是不存在單一數(shù)值型參數(shù)值的特例,無(wú)論有多少參數(shù),無(wú)論參數(shù)是什么類型的,Array.of()方法總會(huì)創(chuàng)建一個(gè)包含所有參數(shù)的數(shù)組
let items = Array.of();
console.log(items.length); // 0
items = Array.of(1, 2);
console.log(items.length); // 2
console.log(items[0]);// 1
console.log(items[1]);// 2
items = Array.of(2);
console.log(items.length); // 1
console.log(items[0]);// 2
items = Array.of("2");
console.log(items.length); // 1
console.log(items[0]);// "2"

[Array.from()]

類數(shù)組對(duì)象
類數(shù)組對(duì)象首先它是一個(gè)對(duì)象,但是有數(shù)組的某些特點(diǎn)。怎么構(gòu)造類數(shù)組對(duì)象呢?先把對(duì)象中的鍵都改為從0開(kāi)始遞增的值,然后我們需要定義一個(gè)length屬性,手動(dòng)模擬數(shù)組的length屬性。
const arrObj = { 0: 'dog', 1: 'cat', 2: 'rabbit', 'length': 3 }
JS不支持直接將非數(shù)組對(duì)象轉(zhuǎn)換為真實(shí)數(shù)組,如果要把它當(dāng)作數(shù)組使用則必須先轉(zhuǎn)換該對(duì)象的類型。在ES5中,可能需要編寫(xiě)如下函數(shù)來(lái)把類數(shù)組對(duì)象轉(zhuǎn)換為數(shù)組

const arguments = { 0: 'dog', 1: 'cat', 2: 'rabbit', 'length': 3 }
function makeArray(arrayLike) { 
  var result = [];   
  for(vari = 0, len = arrayLike.length; i < len; i++) {
    result.push(arrayLike[i]);
  }   
  return result;
}
const args = makeArray(arguments);  // ['dog', 'cat', 'rabbit']
  • 這種方法先是手動(dòng)創(chuàng)建一個(gè)result數(shù)組,再將arguments對(duì)象里的每一個(gè)元素復(fù)制到新數(shù)組中。盡管這種方法有效,但需要編寫(xiě)很多代碼才能完成如此簡(jiǎn)單的操作。最終,開(kāi)發(fā)者們發(fā)現(xiàn)了一種只需編寫(xiě)極少代碼的新方法,調(diào)用數(shù)組原生的slice()方法可以將非數(shù)組對(duì)象轉(zhuǎn)換為數(shù)組
const arguments = { 0: 'dog', 1: 'cat', 2: 'rabbit', 'length': 3 }
const s1 = Array.prototype.slice.call(arguments); // ['dog', 'cat', 'rabbit']
const s2 = Array.prototype.splice.call(arguments, 0); // ['dog', 'cat', 'rabbit']
const s3 = Array.prototype.concat.apply([], arguments); // ['dog', 'cat', 'rabbit']

  • Array.from()方法可以接受可迭代對(duì)象或類數(shù)組對(duì)象作為第一個(gè)參數(shù),最終返回一個(gè)數(shù)組
const arguments = { 0: 'dog', 1: 'cat', 2: 'rabbit', 'length': 3 }
const s = Array.from(arguments) ; // ['dog', 'cat', 'rabbit'] 

[映射轉(zhuǎn)換]

如果想要進(jìn)一步轉(zhuǎn)化數(shù)組,可以提供一個(gè)映射函數(shù)作為Array.from()的第二個(gè)參數(shù),這個(gè)函數(shù)用來(lái)將類數(shù)組對(duì)象中的每一個(gè)值轉(zhuǎn)換成其他形式,最后將這些結(jié)果儲(chǔ)存在結(jié)果數(shù)組的相應(yīng)索引中

const numbers = Array.from([1,2,3], value => value + 1); // [2,3,4]
  • 在這段代碼中,為Array.from()方法傳入映射函數(shù)(value)=>value+1,數(shù)組中的每個(gè)元素在儲(chǔ)存前都會(huì)被加1。如果用映射函數(shù)處理對(duì)象,也可以給Array.from()方法傳入第三個(gè)參數(shù)來(lái)表示映射函數(shù)的this值
let helper ={
  diff: 1,
  add(value) {    
    return value +this.diff;
}
};
function translate() {    
  return Array.from(arguments, helper.add, helper);
}
let numbers = translate(1, 2, 3);
console.log(numbers); // 2,3,4
  • 此示例傳入helper.add()作為轉(zhuǎn)換用的映射函數(shù),由于該方法使用了this.diff屬性,因此需要為Array.from()方法提供第三個(gè)參數(shù)來(lái)指定this的值,從而無(wú)須通過(guò)調(diào)用bind()方法或其他方式來(lái)指定this的值了用Array.from()轉(zhuǎn)換可迭代對(duì)象
  • Array.from()方法可以處理類數(shù)組對(duì)象和可迭代對(duì)象,也就是說(shuō)該方法能夠?qū)⑺泻?code>Symbol.iterator屬性的對(duì)象轉(zhuǎn)換為數(shù)組
let numbers = {   
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  }
};
let numbers2 = Array.from(numbers, (value) => value + 1);
console.log(numbers2); /
  • 由于numbers是一個(gè)可迭代對(duì)象,因此可以直接將它傳入Array.from()來(lái)轉(zhuǎn)換成數(shù)組。此處的映射函數(shù)將每一個(gè)數(shù)字加1,所以結(jié)果數(shù)組最終包含的值為2、3和4

[注意]如果一個(gè)對(duì)象既是類數(shù)組又是可迭代的,那么Array.from()方法會(huì)根據(jù)迭代器來(lái)決定轉(zhuǎn)換哪個(gè)值

2.為所有數(shù)組添加的新方法

ES6延續(xù)了ES5的一貫風(fēng)格,也為數(shù)組添加了幾個(gè)新的方法:includes()方法返回一個(gè)布爾值,表示數(shù)組是否包含給定的值;find()方法和findIndex()方法可以協(xié)助開(kāi)發(fā)者在數(shù)組中查找任意值;fill()方法和copyWithin()方法的靈感則來(lái)自于定型數(shù)組的使用過(guò)程,定型數(shù)組也是ES6中的新特性,是一種只包含數(shù)字的數(shù)組

[1, 2, 3].includes(2)// true
[1, 2, 3].includes(4)// false
[1, 2, NaN].includes(NaN)// true
// 第二個(gè)參數(shù)表示起始位置,默認(rèn)0
// 如果第二個(gè)參數(shù)為負(fù)數(shù),則表示倒數(shù)的位置
// 如果這時(shí)它大于數(shù)組長(zhǎng)度(比如第二個(gè)參數(shù)為-4,但數(shù)組長(zhǎng)度為3),則會(huì)重置為從0開(kāi)始
[1, 2, 3].includes(3, 3);// false
[1, 2, 3].includes(3, -1);// true
  • 沒(méi)有該方法之前,我們通常使用數(shù)組的indexOf方法,檢查是否包含某個(gè)值 。indexOf方法有兩個(gè)缺點(diǎn),一是不夠語(yǔ)義化,它的含義是找到參數(shù)值的第一個(gè)出現(xiàn)位置,所以要去比較是否不等于-1,表達(dá)起來(lái)不夠直觀。二是,它內(nèi)部使用嚴(yán)格相等運(yùn)算符(===)進(jìn)行判斷,這會(huì)導(dǎo)致對(duì)NaN的誤判
if(arr.indexOf(el) !== -1) { 
 // ...
}
// 會(huì)有誤判
[NaN].indexOf(NaN)// -1

另外,MapSet 數(shù)據(jù)結(jié)構(gòu)有一個(gè)has方法,需要注意與includes區(qū)分
1、Map結(jié)構(gòu)的has方法,是用來(lái)查找鍵名的,比如Map.prototype.has(key)、WeakMap.prototype.has(key)、Reflect.has(target,propertyKey)
2、Set結(jié)構(gòu)的has方法,是用來(lái)查找值的,比如Set.prototype.has(value)、WeakSet.prototype.has(value)

[fill()]

let numbers = [1, 2, 3, 4];
numbers.fill(1); // [1,1,1,1]
numbers.fill(99, 2); // [1,2,99,99]
// 從索引為2的位置開(kāi)始,沒(méi)有結(jié)束索引,即填充至最后
numbers.fill(99, 1, 3); // [1,99,99,1]
// 從索引為1的位置開(kāi)始,到索引為3 - 1的位置

[注意]如果開(kāi)始索引或結(jié)束索引為負(fù)值,那么這些值會(huì)與數(shù)組的length屬性相加來(lái)作為最終位置。例如,如果開(kāi)始位置為-1,那么索引的值實(shí)際為array.length-1,array為調(diào)用fill()方法的數(shù)組

[copyWithin()]

copyWithin()方法與fill()方法相似,其也可以同時(shí)改變數(shù)組中的多個(gè)元素。fill()方法是將數(shù)組元素賦值為一個(gè)指定的值,而copyWithin()方法則是從數(shù)組中復(fù)制元素的值。調(diào)用copyWithin()方法時(shí)需要傳入兩個(gè)參數(shù):一個(gè)是該方法開(kāi)始填充值的索引位置,另一個(gè)是開(kāi)始復(fù)制值的索引位置

numbers = [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10];
// 從索引 4的位置開(kāi)始粘貼
// 從數(shù)組索引 0 的位置開(kāi)始復(fù)制數(shù)據(jù)
numbers.copyWithin(4, 0); // [1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
  • 默認(rèn)情況下,copyWithin()會(huì)一直復(fù)制直到數(shù)組末尾的值,但是可以提供可選的第三個(gè)參數(shù)來(lái)限制被重寫(xiě)元素的數(shù)量。第三個(gè)參數(shù)是不包含結(jié)束索引,用于指定停止復(fù)制值的位置
numbers = [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10];
// 從索引 4的位置開(kāi)始粘貼
// 從數(shù)組索引 0 的位置開(kāi)始復(fù)制數(shù)據(jù)
// 在遇到索引 1 時(shí)停止復(fù)制
numbers.copyWithin(4, 0, 1); // [1, 2, 3, 4, 1, 6, 7, 8, 9, 10]
  • 在這個(gè)示例中,由于可選的結(jié)束索引被設(shè)置為了1,因此只有位于索引0的值被復(fù)制了,數(shù)組中的最后一個(gè)元素保持不變

[注意]正如fill()方法一樣,copyWithin()方法的所有參數(shù)都接受負(fù)數(shù)值,并且會(huì)自動(dòng)與數(shù)組長(zhǎng)度相加來(lái)作為最終使用的索引

3.定型數(shù)組

定型數(shù)組是一種用于處理數(shù)值類型(正如其名,不是所有類型)數(shù)據(jù)的專用數(shù)組,支持存儲(chǔ)和操作以下8種不同的數(shù)值類型
無(wú)符號(hào)的8位整數(shù)(uint8)
有符號(hào)的16位整數(shù)(int16)
無(wú)符號(hào)的16位整數(shù)(uint16)
有符號(hào)的32位整數(shù)(int32)
無(wú)符號(hào)的32位整數(shù)(uint32)
32位浮點(diǎn)數(shù)(float32)
64位浮點(diǎn)數(shù)(float64)

不同點(diǎn)

定型數(shù)組與普通數(shù)組最重要的差別是:定型數(shù)組不是普通數(shù)組。它不繼承自Array,通過(guò)Array.isArray()方法檢查定型數(shù)組返回的是false

【數(shù)組緩沖區(qū)】
let buffer = New ArrayBuffer(10) // 分配10字節(jié)
視圖操作
view = new DataView(buffer);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容