深入理解ES6之《改進的陣列功能》

angelayun發表於2017-09-10

Array.of方法

由於Array建構函式建立陣列時的怪異行為,比方說如下:

let items = new Array(2)
console.log(items.length)//2
items = new Array("2")
console.log(items.length)//1

Array.of方法總會建立一個包含所有引數的陣列

let items = Array.of(1, 2)
console.log(items.length)//2
console.log(items[0])//1

Array.of方法不通過Symbol.species屬性確定返回值的型別,它使用當前建構函式,也就是of方法中的this值來確定正確的返回資料的型別

Array.from方法

以前總是使用Array.prototype.slice.call(arrayLike)將類陣列轉換成陣列
Array.from方法可接受可迭代物件或類陣列物件,最終返回一個陣列
Array.from也是通過this來確定返回陣列的型別
Array.from接受第二個引數,表示對映函式,第三個參數列示對映函式中的this的值
來看幾個例子:

function translate() {
    return Array.from(arguments, (value) => value + 1)
}
let numbers = translate(1, 2, 3)
console.log(numbers) //2、3、4
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

看看用Array.from轉換可迭代物件

let numbers = {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
    }
}
let numbers2 = Array.from(numbers, value => value + 1)
console.log(numbers2) //2、3、4

find方法和findIndex方法

find方法和findIndex方法都接受兩個引數,一個是回撥函式,另外一個是可靠引數用於指定回撥函式中this的值


let numbers = [25, 30, 35, 40, 45]
console.log(numbers.find(n => n > 35))//40
console.log(numbers.findIndex(n => n > 35))//3

如果要在陣列中根據某個條件查詢匹配的元素,那麼find方法和findIndex方法可以很好的完成任務,但是如果只想查詢與某個值匹配的元素,則indexOf和lastIndexOf應該是更好的選擇

fill方法

fill方法可以用指定的值填充一至多個陣列元素,當傳入一個值時,fill方法會用這個值重寫陣列中的所有值
fill方法的第二個參數列示開始索引,第三個引數作為不包含結束索引,如果沒有傳第三個引數則預設使用numbers.length作為不包含結束索引
如果開始索引和結束索引為負值,那麼這些值會與陣列的length屬性相加為作為最終位置

copyWithin方法

呼叫copyWithin方法時需要傳入兩個引數,一個是方法開始填充值的索引位置,另一個是開始複製值的索引位置,第三個引數為可選引數,用來限制被重寫元素的數量,也就是指定停止複製值的位置

let numbers = [1, 2, 3, 4]
numbers.copyWithin(2, 0, 1)
console.log(numbers)//1,2,1,4

跟fill方法一樣,copyWithin方法的所有引數都接受負數值,並且會自動與陣列長度相加來作為最終使用的索引

定型陣列

JS中數字是以64位浮點格式儲存並按需轉換成32位整數
陣列緩衝區是所有定型陣列的根基,陣列緩衝區包含的實際位元組數量在建立時就已確定,可以修改緩衝區內的資料,但是不能修改緩衝區的尺寸大小

let buffer = new ArrayBuffer(10)
let buffer2 = buffer.slice(4, 6)
console.log(buffer2.byteLength)//2

陣列緩衝區是記憶體中的一段地址,檢視是用來操作記憶體的介面,檢視可以運算元組緩衝區或緩衝區位元組的子集,並按照其中一種數值型資料型別來讀取和寫入資料

let buffer = new ArrayBuffer(10),
    view1 = new DataView(buffer),
    view2 = new DataView(buffer, 5, 2);
console.log(view1.buffer === buffer)//true
console.log(view2.byteOffset)//5
console.log(view2.byteLength)//2

事實上你可以寫入兩個int8型別的值,然後使用int16型別的方法從緩衝區中讀出這些值

let buffer = new ArrayBuffer(10),
    view = new DataView(buffer);
view.setInt8(0, 5)
view.setInt8(1, -1)
console.log(view.getInt8(0))//5

定型陣列實際上就是用於陣列緩衝區的特定型別的檢視,你可以強制使用特定的資料型別,而不是通過使用通用的DataView物件來運算元組緩衝區
建立定型陣列的方式

1、 通過陣列緩衝區來生成定型陣列的例項

let buffer = new ArrayBuffer(10),
    view = new Int8Array(buffer);
console.log(view.byteLength)

2、通過建構函式中傳入一個數字,這個數字表示分配給陣列的元素數量

let ints = new Int32Array(10);
console.log(ints.byteLength)//20
console.log(ints.length)//10

呼叫定型陣列的建構函式時如果不傳引數,會按照傳入0來處理,這樣由於緩衝區沒有分配到任何位元,因為建立的定型陣列不能用來儲存資料

  1. 可以將定型陣列、可迭代物件、陣列、類陣列物件作為建構函式的引數傳入
let ints1 = new Int16Array([25, 50]),
    ints2 = new Int32Array(ints1);
console.log(ints1.buffer === ints2.buffer)//false
console.log(ints1.length)//2
console.log(ints2.byteLength)//8
console.log(ints2.length)//2
console.log(ints2[0])//25
console.log(ints2[1])//50

每個定型陣列中元素大小指的是每個元素表示的位元組數,該值儲存在每個建構函式和每個例項中BYTES_PER_ELEMENT屬性中

console.log(Uint32Array.BYTES_PER_ELEMENT)

定型陣列和普通陣列的異同點

相同點:
1、可以修改length屬性來改變普通陣列的大小,而定型陣列的length屬性是一個不可寫屬性,所以不能修改定型陣列的大小,如果嘗試修改這個值,在非嚴格模式下會直接忽略該操作,在嚴格模式下會丟擲錯誤
2、定型陣列也包括許多在功能上與普通陣列方法等效的方法,但是定型陣列中的方法會額外的檢查數值型別是否安全
比方說:copyWithin、findIndex、lastIndexOf、slice、entries、forEach、map、some、fill、indexOf、reduce、sort、filter、join、reduceRight、values、find、keys、reverse
3、相同的迭代器(也就是keys、values、entries),這意味著可以把定型陣列當作普通陣列一樣來使用展開運算子、for of 迴圈

let ints = new Int16Array([25, 50]),
    intsArray = [...ints];
console.log(intsArray instanceof Array)//true
console.log(intsArray[0])//25

4、所有定型陣列都包含有靜態of方法和from方法(也就是Array.of和Array.from)
差異點:
1、定型陣列不是普通陣列,它不繼承自Array,通過Array.isArray方法檢測定型陣列返回的是false


let ints = new Int16Array([25, 50])
console.log(ints instanceof Array)//false
console.log(Array.isArray(ints))//false

2、當操作普通陣列時,其可以變大變小,但定型陣列卻始終保持相同的尺寸。給定型陣列中不存在的數值索引賦值會被忽略,而在普通陣列中就可以

let ints = new Int16Array([25, 50]);
console.log(ints.length);//2
console.log(ints[0])//25
console.log(ints[1])//50
ints[2]=5;
console.log(ints.length)//2
console.log(ints[2])//undefined

定型陣列同樣會檢查資料型別的合法性,0被用於代替所有非法值;所有修改定型陣列值的就去執行時都會受到相同限制

let ints = new Int16Array([`hi`])
console.log(ints.length)//1
console.log(ints[0])//0

3、以下方法在定型陣列中不可使用,concat、shift、pop、splice、push、unshift
因為上述列表中除concat外,所有方法都可以改變陣列的尺寸,由於定型陣列的尺寸不可更改,因而這些方法不適用於定型陣列,之所以concat不行是因為兩個定型陣列合並後的結果會變得不確定
4、定型陣列新的附加方法set和subarray
set方法將其它陣列複製到已有的定型陣列
subarray提取已有定型陣列的一部分作為一個新的定型陣列

set方法接受兩個引數:一個是陣列(定型陣列或普通陣列都支援),一個是可選的偏移量,表示開始插入資料的位置,如果什麼都不傳,預設的偏移量是0

let ints = new Int16Array(4);
ints.set([25, 50])
ints.set([75, 100], 2)
console.log(ints)//[25, 50, 75, 100]

subarray方法接受兩個引數:一個是可選的開始位置,一個是可選的結束位置(不包含當前結束位置的值 ),最後返回一個新的定型陣列,也可以省略這兩個引數來克隆一個新的定型陣列

let ints = new Int16Array([25, 50, 75, 100]),
    subInts = ints.subarray(1, 3);
console.log(subInts)//[50, 75]

相關文章