JavaScript陣列的十八般武藝

是方旭啊發表於2018-08-07

陣列

陣列是值的有序集合,每個值叫做一個元素,而每個元素在陣列中有一個位置,以數字表示,稱為索引。

  • JavaScript陣列的索引是基於零的32位數值,第一個元素索引為0,陣列最大能容納4294967295(即2^32-1)個元素。
  • JavaScript陣列是動態的,根據需要它們會增長或縮減,並且在建立陣列時無需宣告一個固定的大小或者在陣列大小變化時無需重新分配空間。
  • JavaScript陣列可能是稀疏的,陣列元素的索引不一定要連續的,它們之間可以有空缺。
  • 每個JavaScript陣列都有一個length屬性,針對非稀疏陣列,該屬性就是陣列元素的個數。針對稀疏陣列,length比所有元素的索引都要大。

建立陣列

1、最簡單的方法是使用陣列直接量(字面量)建立陣列。

var empty = [];     //沒有元素的陣列
var arr = [1.1, true, "a",];    //3個不同型別的元素和結尾的逗號
複製程式碼

陣列直接量中的值也不一定必須是常量,它們可以是任意的表示式:

var number = 1;
var list = [number, number+1, number+2];
複製程式碼

如果省略陣列直接量中的某個值,省略的元素用empty表示(就是沒有這個元素),訪問的話會返回undefined。

var count = [1,,3];     // 陣列列印出來是(3) [1, empty, 3], count[1] === undefined是true。
var undefs = [,,];      // 陣列直接量語法允許有可選的結尾的逗號,顧[,,]只有兩個元素而非三個,undefs.length 是 2
複製程式碼

2、建構函式Array()建立陣列

呼叫時沒有引數,等同於[],建立一個沒有任何元素的空陣列

var arr = new Array();
複製程式碼

呼叫時有一個數值引數,它指定長度

var arr = new Array(10)     // (10) [empty × 10]
複製程式碼

顯式指定兩個或者多個陣列元素或者陣列元素的一個非數值元素

var arr = new Array(1,2,3,"one");
複製程式碼

3、ES6的一些方法

(1)Array.of() 返回由所有引數組成的陣列,不考慮引數的數量或型別,如果沒有引數就返回一個空陣列 (ES6新增)

引數:

elementN 任意個引數,將按順序成為返回陣列中的元素。

注意:

of() 可以解決上述構造器因引數個數不同,導致的行為有差異的問題(引數只有一個數值時,建構函式會把它當成陣列的長度)。

Array.of(1,2,3); // [1,2,3]
Array.of(1,{a:1},null,undefined) // [1, {a:1}, null, undefined]

// 只有一個數值引數時
let B = new Array(3);   // (3) [empty × 3]
let C = Array.of(3);    // [3]
複製程式碼

返回值: 新的 Array 例項。


(2)Array.from()從一個類陣列或可迭代物件中建立一個新的陣列 (ES6新增)

引數:

  • 第一個引數:想要轉換成陣列的類陣列或可迭代物件
  • 第二個引數(可選):回撥函式,類似陣列的map方法,對每個元素進行處理,將處理後的值放入返回的陣列。
  • 第三個引數(可選):繫結回撥函式的this物件
// 有length屬性的類陣列
Array.from({length:5},(v,i) => i)     //[0, 1, 2, 3, 4]

// 部署了Iterator介面的資料結構 比如:字串、Set、NodeList物件
Array.from('hello')    // ['h','e','l','l','o']
Array.from(new Set(['a','b']))   // ['a','b']

// 傳入一個陣列生成的是一個新的陣列,引用不同,修改新陣列不會改變原陣列
let arr1 = [1,2,3]
let arr2 = Array.from(arr);
arr2[1] = 4;
console.log(arr1,arr2)
//[1, 2, 3] [1, 4, 3]
複製程式碼

返回值: 新的 Array 例項。

知識點

//陣列合並去重
function combine(){
    let arr = [].concat.apply([], arguments);  //沒有去重複的新陣列,之後用Set資料結構的特性來去重
    return Array.from(new Set(arr));
}

var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n));
複製程式碼

陣列方法

JavaScript陣列的十八般武藝

1、會改變原陣列的方法

1. push() 方法在陣列的尾部新增一個或多個元素,並返回陣列的長度

引數: item1, item2, ..., itemX ,要新增到陣列末尾的元素

let arr = [1,2,3];
let length = arr.push('末尾1','末尾2');     // 返回陣列長度
console.log(arr,length)
// [1, 2, 3, "末尾1", "末尾2"] 5
複製程式碼

返回值: 陣列的長度


2. pop() 方法刪除陣列的最後一個元素,減小陣列長度並返回它刪除的值

引數:無

//組合使用push()和pop()能夠用JavaScript陣列實現先進後出的棧
let stack = [];
stack.push(1,2) // 返回長度2,這時stack的值是[1,2]
stack.pop()     // 返回刪除的值2,這時stack的值是[1]
複製程式碼

返回值: 從陣列中刪除的元素(當陣列為空時返回undefined)。


3. unshift() 方法在陣列的頭部新增一個或多個元素,並將已存在的元素移動到更高索引的位置來獲得足夠的空間,最後返回陣列新的長度

引數: item1, item2, ..., itemX ,要新增到陣列開頭的元素

let arr = [3,4,5];
let length = arr.unshift(1,2);  // 返回長度是5
console.log(arr, length)
//[1, 2, 3, 4, 5] 5
複製程式碼

注意: 當呼叫unshift()新增多個引數時,引數時一次性插入的,而非一次一個地插入。就像是上例新增1和2,他們插入到陣列中的順序跟引數列表中的順序一致,而不是[2,1,3,4,5]。

返回值: 返回陣列新的長度。


4. shift() 方法刪除陣列的第一個元素並將其返回,然後把所有隨後的元素下移一個位置來填補陣列頭部的空缺,返回值是刪除的元素

引數: 無。

let arr = [1,2,3];
let item = arr.shift(); // 返回刪除的值1
console.log(arr, item)
// [2, 3] 1
複製程式碼

返回值: 從陣列中刪除的元素; 如果陣列為空則返回undefined 。


5. splice() 方法是在陣列中插入或刪除元素的通用方法

語法 array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

引數:

start

指定修改的開始位置(從0計數)。如果超出了陣列的長度,則從陣列末尾開始新增內容;如果是負值,則表示從陣列末位開始的第幾位(從-1計數);若只使用start引數而不使用deleteCount、item,如:array.splice(start) ,表示刪除[start,end]的元素。

deleteCount (可選)

整數,表示要移除的陣列元素的個數。如果 deleteCount 是 0,則不移除元素。這種情況下,至少應新增一個新元素。如果 deleteCount 大於start 之後的元素的總數,則從 start 後面的元素都將被刪除(含第 start 位)。 如果deleteCount被省略,則其相當於(arr.length - start)。

item1, item2, ... (可選)

要新增進陣列的元素,從start 位置開始。如果不指定,則 splice() 將只刪除陣列元素。

返回值: 由被刪除的元素組成的一個陣列。如果只刪除了一個元素,則返回只包含一個元素的陣列。如果沒有刪除元素,則返回空陣列。

// start不超過陣列長度(以下操作是連續的)
let arr = [1,2,3,4,5];
arr.splice(2)   // arr是[1,2],返回值是[3,4,5]
arr.splice(1,1) // arr是[1],返回值是[2]
arr.splice(0,3) // arr是[],返回值是[1],因為此時陣列從第0位開始不夠3位,所以是刪除從0開始到最後的所有元素。

// start大於陣列長度(以下操作是連續的)
let arr = [1,2,3,4,5];
arr.splice(5)   // arr是[1,2,3,4,5],返回值是[]
arr.splice(5,3,6) // arr是[1,2,3,4,5,6],返回值是[]
arr.splice(5,3,7) // arr是[1,2,3,4,5,7] 返回值是[6]

// start是負數(以下操作是連續的)
let arr = [1,2,3,4,5];
arr.splice(-3,2); // arr是[1,2,5], 返回值是[3,4]
arr.splice(-4); // arr是[],返回值是[1,2,5]

// 插入陣列時,是插入陣列本身,而不是陣列元素
let arr = [1,4,5];
arr.splice(1,0,[2,3])   // arr是[1,[2,3],4,5],返回值是[]
複製程式碼

6. sort() 方法將陣列中的元素排序並返回排序後的陣列

引數:

compareFunction (可選) 用來指定按某種順序進行排列的函式。如果省略,元素按照轉換為的字串的各個字元的Unicode位點進行排序。 如果指明瞭 compareFunction ,那麼陣列會按照呼叫該函式的返回值排序。即 a 和 b 是兩個將要被比較的元素:

  • 如果 compareFunction(a, b) 小於 0 ,那麼 a 會被排列到 b 之前;
  • 如果 compareFunction(a, b) 等於 0 , a 和 b 的相對位置不變。備註: ECMAScript 標準並不保證這一行為,而且也不是所有瀏覽器都會遵守(例如 Mozilla 在 2003 年之前的版本);
  • 如果 compareFunction(a, b) 大於 0 , b 會被排列到 a 之前。
  • compareFunction(a, b) 必須總是對相同的輸入返回相同的比較結果,否則排序的結果將是不確定的。
var stringArray = ["Blue", "Humpback", "Beluga"];
var numberArray = [40, 1, 5, 200];
function compareNumbers(a, b){
  return a - b;
}
console.log('stringArray:' + stringArray.join());
console.log('Sorted:' + stringArray.sort());

console.log('numberArray:' + numberArray.join());
// 沒有使用比較函式時,數字並不會按照我們設想的那樣排序
console.log('Sorted without a compare function:'+ numberArray.sort());
console.log('Sorted with compareNumbers:'+ numberArray.sort(compareNumbers));

//列印如下
// stringArray: Blue,Humpback,Beluga
// Sorted: Beluga,Blue,Humpback

// numberArray: 40,1,5,200
// Sorted without a compare function: 1,200,40,5
// Sorted with compareNumbers: 1,5,40,200
複製程式碼

返回值: 返回排序後的陣列。原陣列已經被排序後的陣列代替。


7. reverse() 方法將陣列中的元素顛倒順序,返回逆序的陣列。

引數: 無

let arr = [1,2,3];
arr.reverse()   // arr是[3,2,1],返回值是[3,2,1]
複製程式碼

返回值: 返回順序顛倒後的陣列。原陣列已經被排序後的陣列代替。


8. copyWithin() 方法淺複製陣列的一部分到同一陣列中的另一個位置,並返回它,而不修改其大小。 (ES6新增)

語法: arr.copyWithin(target[, start[, end]])

引數:

target

0 為基底的索引,複製序列到該位置。如果是負數,target 將從末尾開始計算。

如果 target 大於等於 arr.length,將會不發生拷貝。如果 target 在 start 之後,複製的序列將被修改以符合 arr.length。

start

0 為基底的索引,開始複製元素的起始位置。如果是負數,start 將從末尾開始計算。

如果 start 被忽略,copyWithin 將會從0開始複製。

end

0 為基底的索引,開始複製元素的結束位置。copyWithin 將會拷貝到該位置,但不包括 end 這個位置的元素。如果是負數, end 將從末尾開始計算。

如果 end 被忽略,copyWithin 將會複製到 arr.length。

返回值: 改變了的陣列。

[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]

[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(-2, -3, -1);
// [1, 2, 3, 3, 4]


// copyWithin 函式是設計為通用的,其不要求其 this 值必須是一個陣列物件。
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
複製程式碼

9. fill() 方法用一個固定值填充一個陣列中從起始索引到終止索引內的全部元素。 (ES6新增)

語法: arr.fill(value[, start[, end]])

引數:

value 用來填充陣列元素的值。

start (可選) 起始索引,預設值為0。

end (可選) 終止索引,預設值為 this.length。

如果 start 是個負數, 則開始索引會被自動計算成為 length+start, 其中 length 是 this 物件的 length 屬性值. 如果 end 是個負數, 則結束索引會被自動計算成為 length+end。

返回值: 修改後的陣列

[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);         // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3);         // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);       // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN);     // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5);         // [1, 2, 3]
Array(3).fill(4);                // [4, 4, 4]

//fill 方法故意被設計成通用方法, 該方法不要求 this 是陣列物件。
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}
複製程式碼

2、不改變原陣列的方法

1. slice() 方法返回一個從開始到結束(不包括結束)選擇的陣列的一部分淺拷貝到一個新陣列物件。且原始陣列不會被修改。

引數:

begin (可選)

從該索引處開始提取原陣列中的元素(從0開始)。

如果該引數為負數,則表示從原陣列中的倒數第幾個元素開始提取,slice(-2)表示提取原陣列中的倒數第二個元素到最後一個元素(包含最後一個元素)。

如果省略 begin,則 slice 從索引 0 開始。

end (可選)

在該索引處結束提取原陣列元素(從0開始)。

slice會提取原陣列中索引從 begin 到 end 的所有元素(包含begin,但不包含end)。 slice(1,4) 提取原陣列中的第二個元素開始直到第四個元素的所有元素 (索引為 1, 2, 3的元素)。

如果該引數為負數, 則它表示在原陣列中的倒數第幾個元素結束抽取。 slice(-2,-1)表示抽取了原陣列中的倒數第二個元素到最後一個元素(不包含最後一個元素,也就是隻有倒數第二個元素)。

如果 end 被省略,則slice 會一直提取到原陣列末尾。

如果 end 大於陣列長度,slice 也會一直提取到原陣列末尾

返回值: 一個含有提取元素的新陣列

let arr = [1,2,3,4,5];
let arr1 = arr.slice(1,3); // arr是[1,2,3,4,5], arr1是[2,3]
let arr2 = arr.slice(-2,-1);  // arr是[1,2,3,4,5], arr2是[4]
// 開始位置在結束位置後面,得到的陣列是空
let arr3 = arr.slice(-2, -3); // arr是[1,2,3,4,5], arr3是[]
let arr4 = arr.slice(2, 1); // arr是[1,2,3,4,5], arr4是[]

//如果元素是個物件引用 (不是實際的物件),slice 會拷貝這個物件引用到新的陣列裡。兩個物件引用都引用了同一個物件。如果被引用的物件發生改變,則新的和原來的陣列中的這個元素也會發生改變。
let arr = [{name: 'xiaoming'}];
let arr1 = arr.slice(); // arr是[{name: xiaoming}],arr1是[{name: 'xiaoming'}]
arr1[0].name = 'xiaogang'; // arr是[{name: 'xiaogang'}],arr1是[{name: 'xiaogang'}]

// 對於字串、數字及布林值來說(不是 String、Number 或者 Boolean 物件),slice 會拷貝這些值到新的陣列裡。在別的陣列裡修改這些字串或數字或是布林值,將不會影響另一個陣列。
let arr = [1,2,3];
let arr1 = arr.slice(); // arr是[1,2,3],arr1是[1,2,3]
arr1[1] = "two"; // arr是[1,2,3],arr1是[1,"two",3]

// 當然,如果向兩個陣列任一中新增了新元素(簡單或者引用型別),則另一個不會受到影響。
複製程式碼

2. join() 方法將陣列(或一個類陣列物件)中所有元素都轉化為字串並連線在一起,返回最後生成的字串。

引數:

separator (可選) 指定一個字串來分隔陣列的每個元素。 如果有(separator),將分隔符轉換為字串。 如果省略(),陣列元素用逗號分隔。預設為 ","。 如果separator是空字串(""),則所有元素之間都沒有任何字元。

let num = [1,2,3];
let str1 = num.join(); // 1,2,3
let str2 = num.join(', ') // 1, 2, 3
let str3 = num.join('') // 123

//所有的陣列元素被轉換成字串,再用一個分隔符將這些字串連線起來。如果元素是undefined 或者null, 則會轉化成空字串。
let num = [1,null,3];
let str1 = num.join(); // 1,,3

//如果陣列中的元素是陣列,會將裡面的陣列也呼叫join()
let num = [[1,2],3];
let str1 = num.join('-'); // 1,2-3

// 如果陣列中的元素是物件,物件會被轉為[object Object]字串
let num = [{num: 1},2,3];
let str1 = num.join('-'); // [object Object]-2-3
複製程式碼

返回值: 一個所有陣列元素連線的字串。如果 arr.length 為0,則返回空字串

知識點

// 扁平化簡單的二維陣列
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.join().split(','); // ["11", "22", "33", "44", "55", "66"]
複製程式碼

3. toString() 方法將陣列的每個元素轉化為字串(如有必要將呼叫元素的toString()方法)並且輸出用逗號分割的字串列表。返回一個字串表示陣列中的元素

引數:

[1,2,3].toString(); // 1,2,3
[1,[2,'c']].toString(); //1,2,c
// 以上與不使用任何引數呼叫join()方法返回的字串是一樣的。

// 以下的這個例子要跟下面的toLocaleString對照看
[{a:1},1,new Date()].toString() //"[object Object],1,Sat Jul 07 2018 18:43:45 GMT+0800 (中國標準時間)"
複製程式碼

注意: 當陣列和字串操作的時候,js 會呼叫這個方法將陣列自動轉換成字串

[1,2,3]+'abc'  //1,2,3abc
複製程式碼

返回值: 返回一個字串表示陣列中的元素

知識點

// 扁平化簡單的二維陣列
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.toString().split(','); // ["11", "22", "33", "44", "55", "66"]
複製程式碼

4. toLocaleString() 陣列中的元素將使用各自的 toLocaleString 方法轉成字串,這些字串將使用一個特定語言環境的字串(例如一個逗號 ",")隔開。

引數:(還有待考證,我試了一下沒用,看了一下ECMA的官網,確實是標註有兩個可選引數的)

locales (可選) 帶有BCP 47語言標記的字串或字串陣列

options (可選) 一個可配置屬性的物件

//陣列中的元素將會使用各自的 toLocaleString 方法:
// Object: Object.prototype.toLocaleString()
// Number: Number.prototype.toLocaleString()
// Date: Date.prototype.toLocaleString()

let prices = ['¥7', 500, 8123, 12];

// 不帶引數
prices.toLocaleString(); // "¥7,500,8,123,12"

//帶引數
prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }); // "¥7,500,8,123,12"
//MDN上的舉例中說是 "¥7,¥500,¥8,123,¥12",在瀏覽器和Node中驗證了返回的都是 "¥7,500,8,123,12" 啊!

// 以下的這個例子要跟上面的toString對照看
[{a:1},1,new Date()].toLocaleString() //"[object Object],1,2018/7/7 下午6:45:00"
複製程式碼

返回值: 表示陣列元素的字串。


5. concat() 方法用於合併兩個或多個陣列。此方法不會更改現有陣列,而是返回一個新陣列。

它的元素包括呼叫concat()的原始陣列的元素和concat()的每個引數,但是要注意,concat()不會遞迴扁平化陣列的陣列,concat()也不會修改呼叫的陣列。

引數:

valueN (可選) 將(多個)陣列和/或值連線成新陣列。

[1,2,3].concat([4,5,6],[7,8,9]) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

['a','b','c'].concat(1,[2,3],[[4,5]]) // ["a", "b", "c", 1, 2, 3, [4,5]]

// concat方法不會改變this或任何作為引數提供的陣列,而是返回一個淺拷貝,所以原始陣列和新陣列都引用相同的物件。 如果引用的物件被修改,新陣列和原始陣列都會變。
let obj = {a: 1};
let arr1 = [2,obj];
let arr2 = [1].concat(arr1);
console.log(arr1,arr2) //[2,{a:1}],[1,2,{a:1}]

//記錄下上面的列印結果之後修改obj
obj.a = 2;
console.log(arr1,arr2) ////[2,{a:2}],[1,2,{a:2}]

// 說了是淺拷貝,而且原陣列也不改變,那我們就可以用它來實現陣列的淺拷貝功能
let num1 = [1,2,3];
//第一種
let num2 = num1.concat();
//第二種
let num2 = [].concat(num1);
num2[0] = 'a';
console.log(num1,num2); // [1, 2, 3] ["a", 2, 3]
複製程式碼

返回值: 新的 Array 例項

知識點

// concat 和擴充套件運算子可以快速扁平化陣列
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = [].concat(...arr); // [11, 22, 33, 44, 55, 66]
複製程式碼

6. isArray() 用於確定傳遞的值是否是一個 Array。

引數:

obj 需要檢測的值。

// 下面的函式呼叫都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 這裡注意:Array.prototype 也是一個陣列,一個屬性值不是索引的陣列。[constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]
Array.isArray(Array.prototype);

// 下面的函式呼叫都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
複製程式碼

返回值: 如果物件是 Array,則為true; 否則為false。

知識點

//判斷陣列的歷程
// step one: 使用constructor
var a = [1];
console.log(a.constructor === Array) // true
// 但是原型的contructor屬性是可以被改寫的,例如在原型繼承的時候,我們都是要把繼承過來的prototype的constructor改寫成我們當前的
var a = [1];
a.__proto__.constructor = '1';
console.log(a.constructor === Array) // false

// step two : 使用instanceof
var a = [1];
console.log(a instanceof Array) // true
//但是instanceof不能檢測iframes的陣列
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]

arr instanceof Array; // false

// step three :萬無一失的Object.prototype.toString.call
Array.isArray = function(arg) {
  return Object.prototype.toString.call(arg) === '[object Array]';
};

// step four : Array.isArray()

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]

Array.isArray(arr);  // true,也可以檢測iframes的陣列

複製程式碼

3、陣列遍歷、對映、過濾、檢測、簡化等方法

介紹方法之前,先對這些陣列方法做一個概述:

  • 首先,大多數方法的第一個引數接收一個函式,並且對陣列的每個元素(或一些元素)呼叫一次該函式。如果是稀疏陣列,對不存在的元素不呼叫該函式。大多數情況下,呼叫提供的函式使用三個引數:陣列元素、元素的索引和陣列本身。通常,只需要第一個引數值,可以忽略後兩個引數。

  • 大多數方法,第二個引數是可選的。如果有第二個引數,則呼叫的第一個函式引數被看做是第二個引數的方法,即當執行第一個函式引數時用作this的值(參考物件)。

  • 方法的返回值很重要,不同的方法處理返回值的方式也不一樣。

下面這些方法執行時的規則:

  1. 對於空陣列是不會執行回撥函式的
  2. 對於已在迭代過程中刪除的元素,或者空元素會跳過回撥函式
  3. 遍歷次數在第一次迴圈前就會確定,再新增到陣列中的元素不會被遍歷。
  4. 如果已經存在的值被改變,則傳遞給 callback 的值是遍歷到他們那一刻的值。
  5. 已刪除的項不會被遍歷到。如果已訪問的元素在迭代時被刪除了(例如使用 shift()) ,之後的元素將被跳過

1. forEach() 方法從頭到尾遍歷陣列,為每個元素呼叫指定的函式。

引數:

callback 為陣列中每個元素執行的函式,該函式接收三個引數:

  1. currentValue(當前值) 陣列中正在處理的當前元素。
  2. index(索引) 陣列中正在處理的當前元素的索引。
  3. array forEach()方法正在操作的陣列。

thisArg (可選) 當執行回撥函式時用作this的值(參考物件)。預設值為undefined

注意:

  1. forEach無法中途退出迴圈,只能用return退出本次回撥,進行下一次回撥,如果要提前終止,可以把forEach方法放在try塊中,並能丟擲一個異常,但這種方法是不推薦的。
  2. 它與之後會說到的幾個方法不同,總是返回 undefined值,即使你return了一個值。
// 1、 空元素不遍歷,undefined和null是會遍歷的。
let numberArr = [1,2,,3];
numberArr.forEach(function (value,index,array) {
  console.log(value,index,array)
})
//列印資訊如下,可見空元素是不會遍歷的
//1 0 [1, 2, empty, 3]
//2 1 [1, 2, empty, 3]
//3 3 [1, 2, empty, 3]

let nullArr = [1,2,null,3];
nullArr.forEach(function (value,index,array) {
  console.log(value,index,array)
})
//列印資訊如下,null是會遍歷的
//1 0 (4) [1, 2, null, 3]
//2 1 (4) [1, 2, null, 3]
//null 2 (4) [1, 2, null, 3]
//3 3 (4) [1, 2, null, 3]

//2、已刪除的項不會被遍歷到。如果已訪問的元素在迭代時被刪除了,之後的元素將被跳過
let numberArr = [1,2,3];
numberArr.forEach(function (value,index,array) {
  if(index === 0) {
    delete numberArr[2]; //刪除第三項
    //或者numberArr.pop()
  }
  console.log(value,index,array)
})
//列印資訊如下:
// 1 0 (3) [1, 2, empty]
// 2 1 (3) [1, 2, empty]


let numberArr1 = [1,2,3,4];
numberArr1.forEach(function (value,index,array) {
  if(index === 1) {
    numberArr1.shift() //遍歷到第二項的時候,刪除第一項
  }
  console.log(value,index,array)
})
// 列印資訊如下,遍歷到第二項的時候,刪除第一項,會跳過第三項
// 1 0 (4) [1, 2, 3, 4]
// 2 1 (3) [2, 3, 4]
// 4 2 (3) [2, 3, 4]

// 3、forEach 遍歷的範圍在第一次呼叫 callback 前就會確定。呼叫forEach 後新增到陣列中的項不會被 callback 訪問到。如果已經存在的值被改變,則傳遞給 callback 的值是 forEach 遍歷到他們那一刻的值。
let arr = [1,2,3];
arr.forEach(function (value,index,array) {
  if(index === 0) {
    arr.push('新增的不會被遍歷到')
    arr[2] = 4;
  }
  console.log(value,index,array)
})
// 1 0 (4) [1, 2, 4, "新增的不會被遍歷到"]
// 2 1 (4) [1, 2, 4, "新增的不會被遍歷到"]
// 4 2 (4) [1, 2, 4, "新增的不會被遍歷到"]

// 4、使用thisArg引數 和 箭頭函式使用thisArg
let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(function () {
  console.log(this.arr)
},obj)
// 列印三次 'thisArg'

let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(() => {
  console.log(this.arr)
},obj)
// 列印三次 undefined

// 5、forEach無法中途退出迴圈,只能用return退出本次回撥,進行下一次回撥
let arr = [1,2,3];
let result = arr.forEach((value) => {
  if(value == 2) {
    return value;
  }
  console.log(value)
})
console.log(result) // undefined ,即使中間return vlaue,也還是undefined
//列印value的值如下,說明return 並不能終止迴圈
// 1
// 3

複製程式碼

返回值: undefined


2. map() 方法建立一個新陣列,其結果是該陣列中的每個元素都呼叫一個callback函式後返回的結果。

引數:(之前說過,大多說方法都會是這樣一些引數)

callback 生成新陣列元素的函式,使用三個引數這個函式跟forEach()的函式不同的是,傳遞給map()的函式應該有返回值。

  1. currentValue callback 的第一個引數,陣列中正在處理的當前元素。
  2. index callback 的第二個引數,陣列中正在處理的當前元素的索引。
  3. array callback 的第三個引數,map 方法被呼叫的陣列。

thisArg (可選) 執行 callback 函式時 使用的this 值。

注意: map() 返回的是新陣列,它不修改呼叫的陣列。如果是稀疏陣列,返回的也是相同方式的稀疏陣列:它具有相同的長度,相同索引的缺失元素(因為空值不會呼叫函式)

let number = [1,2,3];
let doubles = number.map(function (value) {
  return value * 2;
})
console.log(number, doubles)
// [1,2,3] [2,4,6]

複製程式碼

返回值: 一個新陣列,每個元素都是回撥函式的結果

知識點 不要用 map 代替 forEach,map 會建立一個新的陣列,佔用記憶體。如果你不用 map 的返回值,那你就應當使用 forEach


3. filter() 方法返回的陣列元素是呼叫的陣列的一個子集。傳入的函式時用來邏輯判定的,該函式返回 true 或 false,如果返回值為true或能轉化為true的值,那麼傳遞給判斷函式的元素就是這個子集的成員,它將被新增倒一個作為返回值的陣列中。

引數:

callback 用來測試陣列的每個元素的函式。呼叫時使用引數 (element, index, array)。返回true表示保留該元素(通過測試),false則不保留。它接受三個引數:

  1. element 當前在陣列中處理的元素
  2. index(可選) 正在處理元素在陣列中的索引
  3. array(可選)呼叫了filter篩選器的陣列

thisArg(可選)可選。執行 callback 時的用於 this 的值。

注意:

  1. callback 只會在已經賦值的索引上被呼叫,對於那些已經被刪除或者從未被賦值的索引不會被呼叫。也就是說filter()會跳過稀疏陣列中缺少的元素,它的返回陣列總是稠密的,可以用這個方法壓縮稀疏陣列的空缺。
  2. filter 不會改變原陣列,它返回過濾後的新陣列。
let number = [1,2,3,4,5,6];
let small = number.filter((value) => {
  return value < 4;
})
console.log(number,small)
// 列印 [1, 2, 3, 4, 5, 6] [1, 2, 3]


//壓縮稀疏陣列的空缺
let arr = [1,2,3,,5];
let arr1 = arr.filter(() => true);
console.log(arr,arr1)
// 列印 [1, 2, 3, empty, 5] [1, 2, 3, 5]

複製程式碼

返回值: 一個新的通過測試的元素的集合的陣列,如果沒有通過測試則返回空陣列。


4. every() 方法測試陣列的所有元素是否都通過了指定函式的測試。當且僅當針對陣列中的所有元素呼叫判定函式都返回true,它才返回true。

引數:

callback 用來測試每個元素的函式。

thisArg 執行 callback 時使用的 this 值。

注意:

  1. every 方法為陣列中的每個元素執行一次 callback 函式,callback 只會為那些已經被賦值的索引呼叫。不會為那些被刪除或從來沒被賦值的索引呼叫。every 方法在callback第一次返回false後就返回false,然後終止遍歷。但如果callback一直返回true,它將會遍歷整個陣列,最終返回true。
  2. 空陣列上呼叫every方法,返回 true,因為空陣列沒有元素,所以空陣列中所有元素都符合給定的條件
  3. every 不會改變原陣列
let arr = [12,34,5,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
  num++;
  return element > 10;
})
console.log(result,num) // 列印 false 3
// 可見發現5這個小於10的元素後,遍歷立即終止,num為3

let arr = [12,34,,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
  num++;
  return element > 10;
})
console.log(result,num) // 列印 true 4
// 不會遍歷沒有賦值的索引位置,所以num為4

let result = [].every(function (element, index, array) {
  return element > 10;
})

console.log(result) // 列印 true


複製程式碼

返回值: 一個布林值,當所有的元素都符合條件才返回true,否則返回false


5. some() 方法測試陣列中的某些元素是否通過由提供的函式實現的測試。當陣列中至少有一個元素呼叫判定函式返回true,它就返回true,當且僅當陣列中的所有元素呼叫判定函式都返回false,它才返回false。

引數:

callback 用來測試每個元素的函式

thisArg 可選 執行 callback 時使用的 this 值。

注意:

  1. some 為陣列中的每一個元素執行一次 callback 函式,直到找到一個使得 callback 返回一個“真值”,這時,some 將會立即返回 true。否則,some 返回 false。callback 只會在那些”有值“的索引上被呼叫,不會在那些被刪除或從來未被賦值的索引上呼叫。
  2. some 被呼叫時不會改變陣列。
  3. 空陣列呼叫some,返回false
// 一個簡單的例子說明
function isBiggerThan10(element, index, array) {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

// 實現一個跟includes方法類似的功能
let arr = [1,2,3];
function include(value) {
  return arr.some((element) => {
    return element === value;
  })
}
include(2) // true
include(4) // false

let result = [].some(function (element, index, array) {
  return element > 10;
})

console.log(result) // 列印 false
複製程式碼

返回值: 只要陣列中的任意一個元素在回撥函式中返回的是真值,就返回true,否則為false


6. reduce() 和 reduceRight() 這兩個方法使用指定的函式將陣列元素進行組合,生成單個值。這在函數語言程式設計中是常見的操作,也可以稱為“注入”和“摺疊”。reduceRight() 和 reduce() 工作原理是一樣的,不同的是reduceRight() 按照陣列索引從高到低(從右到左)處理陣列,而不是從低到高。

引數:

callback 執行陣列中每個值的函式,包含四個引數:

  1. accumulator 累加器累加回撥的返回值; 它是上一次呼叫回撥時返回的累積值,或initialValue(如下所示)。
  2. currentValue 陣列中正在處理的元素。
  3. currentIndex (可選) 陣列中正在處理的當前元素的索引。 如果提供了initialValue,則索引號為0,否則為索引為1。
  4. array (可選) 呼叫reduce的陣列

initialValue (可選) 用作第一個呼叫 callback的第一個引數的值。 如果沒有提供初始值,則將使用陣列中的第一個元素。 在沒有初始值的空陣列上呼叫 reduce 將報錯。

注意:

  1. reduce為陣列中的每一個元素依次執行callback函式,不包括陣列中被刪除或從未被賦值的元素,回撥函式第一次執行時,accumulator 和currentValue的取值有兩種情況:呼叫reduce時提供initialValue,accumulator取值為initialValue,currentValue取陣列中的第一個值;沒有提供 initialValue,accumulator取陣列中的第一個值,currentValue取陣列中的第二個值。即:如果沒有提供initialValue,reduce 會從索引1的地方開始執行 callback 方法,跳過第一個索引。如果提供initialValue,從索引0開始。

  2. 如果陣列為空且沒有提供initialValue,會丟擲TypeError 。如果陣列僅有一個元素(無論位置如何)並且沒有提供initialValue, 或者有提供initialValue但是陣列為空,那麼此唯一值將被返回並且callback不會被執行

let arr = [1,2,3,4,5];
let sum = arr.reduce((x,y) => x + y,0);
console.log(sum) // 15

// 看一下initialValue傳和不傳的區別
let arr = [1,2,3,4,5];
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
  console.log(currentIndex)
  return accumulator + currentValue;
})
// 1,2,3,4,5 沒傳入initialValue,索引是從1開始
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
  console.log(currentIndex)
  return accumulator + currentValue;
},10)
// 0,1,2,3,4,5 傳入initialValue,索引從0開始

// 應用到二維陣列展開
let arr = [[0, 1], [2, 3], [4, 5]].reduce(
  (a, b) => a.concat(b)
);
console.log(arr)
// [0, 1, 2, 3, 4, 5]
複製程式碼

返回值: 函式累計處理的結果


7. indexof() 方法返回在陣列中可以找到一個給定元素的第一個索引,如果不存在,則返回-1。

引數:

searchElement 要查詢的元素

fromIndex (可選)開始查詢的位置。 如果該索引值大於或等於陣列長度,意味著不會在陣列裡查詢,返回-1。

如果該索引值是負值,代表相對陣列末尾的偏移量,即-1表示從最後一個元素開始查詢,-2表示從倒數第二個元素開始查詢,注意的是,這並不改變其查詢順序,查詢順序仍然是從前向後查詢陣列。

如果該索引值是負值,其絕對值大於陣列長度,則整個陣列都將會被查詢。其預設值為0。

注意: indexOf 使用嚴格相等(即 ===)比較 searchElement 和陣列中的元素。而且indexOf()不能識別 NaN

let array = [2, 5, 9];
array.indexOf(2)     // 0
array.indexOf(7)     // -1
array.indexOf(9, 2)  // 2
array.indexOf(9, 3)  // -1
array.indexOf(2, -1) // -1
array.indexOf(2, -3) // 0
array.indexOf(2, -4) // 0

let array1 = [1,2,NaN];
array1.indexOf(NaN) // -1
複製程式碼

返回值: 首個被找到的元素在陣列中的索引位置; 若沒有找到則返回 -1


8. lastIndexOf() 跟indexOf()查詢方向相反,方法返回指定元素在陣列中的最後一個的索引,如果不存在則返回 -1。從陣列的後面向前查詢,從 fromIndex 處開始

引數:

searchElement 要查詢的元素

fromIndex (可選)開始查詢的位置。預設為陣列的長度減 1,即整個陣列都被查詢。 如果該值大於或等於陣列的長度,則整個陣列會被查詢。 如果為負值,將其視為從陣列末尾向前的偏移。即使該值為負,陣列仍然會被從後向前查詢。 如果該值為負時,其絕對值大於陣列長度,則方法返回 -1,即陣列不會被查詢。

注意: lastIndexOf 使用嚴格相等(即 ===)比較 searchElement 和陣列中的元素。而且lastIndexOf()不能識別 NaN

let array = [2,5,9,2];
array.lastIndexOf(9) // 2
array.lastIndexOf('9') // -1 嚴格相等
array.lastIndexOf(7) // -1
array.lastIndexOf(2,4) // 3
array.lastIndexOf(2,3) // 3
array.lastIndexOf(2,2) // 0
array.lastIndexOf(2,-1) // 3
array.lastIndexOf(2,-2) // 0
array.lastIndexOf(2,-4) // 0
array.lastIndexOf(2,-5) // -1
複製程式碼

返回值: 陣列中最後一個符合元素的索引,如未找到返回-1


9. includes() 方法用來判斷一個陣列是否包含一個指定的值,根據情況,如果包含則返回 true,否則返回false。 ES7新增

引數:

searchElement 需要查詢的元素值。

fromIndex (可選) 從該索引處開始查詢 searchElement。預設為 0。如果為負值,則按升序從 array.length + fromIndex 的索引開始搜尋。負值絕對值超過長陣列度,從0開始搜尋。

如果fromIndex 大於等於陣列長度 ,則返回 false 。該陣列不會被搜尋。

注意:

includes解決了兩個indexOf的問題:

  1. indexOf方法不能識別NaN
  2. indexOf方法檢查是否包含某個值不夠語義化,需要判斷是否不等於-1,表達不夠直觀
[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, 3].includes(3, -4); // true
[1, 2, NaN].includes(NaN); // true
複製程式碼

返回值: 一個布林值,根據情況,如果包含則返回 true,否則返回false。


10. find() 和 findIndex() find 方法返回陣列中滿足提供的測試函式的第一個元素的值。否則返回 undefined。findIndex 方法返回陣列中滿足提供的測試函式的第一個元素的索引。否則返回-1。(ES6新增)

引數: 這兩個方法跟其他的方法類似

callback 在陣列每一項上執行的函式,接收 3 個引數:

  1. element 當前遍歷到的元素。
  2. index 當前遍歷到的索引。
  3. array 陣列本身。

thisArg 可選,指定 callback 的 this 引數。

注意:

  1. 這兩個方法對陣列中的每一項元素執行一次 callback 函式,直至有一個 callback 返回 true。在稀疏陣列中,即使對於陣列中不存在的條目的索引也會呼叫回撥函式。 這意味著對於稀疏陣列來說,該方法的效率要低於那些只遍歷有值的索引的方法。
  2. 當找到一個callback判斷為true的元素,find方法會立即返回這個元素的值,否則返回 undefined。findIndex會立即返回該元素的索引。如果回撥從不返回真值,或者陣列的length為0,則findIndex返回-1。
  3. 這兩個方法都不會修改所呼叫的陣列
// find
let a = [1, 4, -5, 10].find((n) => n < 0); // 返回元素-5
let b = [1, 4, -5, 10,NaN].find((n) => Object.is(NaN, n));  // 返回元素NaN
// findIndex
let a = [1, 4, -5, 10].findIndex((n) => n < 0); // 返回索引2
let b = [1, 4, -5, 10,NaN].findIndex((n) => isNaN(n));  // 返回索引4

// 稀疏陣列
let a =[1,,3,4];
let index = 0;
a.find((n) => {
  console.log(index++) //0,1,2 第二次是empty也會呼叫一次,而且返回為true,立即退出 
  return n === 3;
})
複製程式碼
**返回值:**
  1. find 方法,當某個元素通過 callback 的測試時,返回陣列中的一個值,否則返回 undefined。
  2. findIndex方法,返回陣列中滿足提供的測試函式的第一個元素的索引。否則返回-1。

知識點 不要用 find() 代替 some(),通常混用是這種場景,find 返回第一個符合條件的值,直接拿這個值做 if 判斷是否存在,但是這個符合條件的值也有可能恰好為 0。 find 是找到陣列中的值後對其進一步處理,一般用於物件陣列的情況;some 才是檢查存在性;兩者不可混用。


11. keys() 方法返回一個新的Array迭代器,它包含陣列中每個索引的鍵。 (ES6新增)

12. values() 方法返回一個新的Array迭代器,它包含陣列中每個索引的值。 (ES6新增)

13. @@iterator 屬性和 values() 屬性的初始值均為同一個函式物件。陣列的 iterator 方法,預設情況下與 values() 返回值相同,呼叫語法是 arr[Symbol.iterator]() (ES6新增)

14. entries() 方法返回一個新的Array迭代器,該物件包含陣列中每個索引的鍵/值對。 (ES6新增)

引數: 都是無。

都是一個新的 Array 迭代器物件。

for (let key of ['a', 'b'].keys()) {
  console.log(key);
}
// 0
// 1

for (let value of ['a', 'b'].values()) {
  console.log(value);
}
// 'a'
// 'b'

for (let value of ['a', 'b'][Symbol.iterator]()) {
  console.log(value);
}
// 'a'
// 'b'

for (let [key, value] of ['a', 'b'].entries()) {
  console.log(key, value);
}
// 0 "a"
// 1 "b"
複製程式碼

擴充套件幾個概念

1、陣列的索引和物件key有什麼關係?

陣列是物件的特殊形式,使用方括號訪問陣列元素和使用方括號訪問物件屬性一樣。JavaScript將指定的數字索引值轉換成字串——索引1變成"1"——然後將其作為屬性名來使用。陣列的特別之處在於,當使用小於2^32的非負整數作為屬性名時陣列會自動維護其length屬性。

// 索引到屬性名的轉化
let arr = [1,2,3];
console.log(arr[1]) // 2
console.log(arr["1"]) // 2
複製程式碼

所有的陣列都是物件,可以為其建立任意名字的屬性,不過,只有在小於2^32的非負整數才是索引,陣列才會根據需要更新length。事實上陣列的索引僅僅是物件屬性名的一種特殊型別,這意味著JavaScript陣列沒有“越界”錯誤的概念。當查詢任何物件中不存在的屬性時,不會報錯,只會得到undefined

let arr = [];
arr["a"] = 1;
console.log(arr,arr.length) // arr是[a:1] length是0
複製程式碼

對於使用負數或非整數的情況,數值會轉換為字串,字串作為屬性名來用,當時只能當做常規的物件屬性,而非陣列的索引。

let arr = [];
arr[-1.23] = 0;
console.log(arr,arr.length) // arr是[-1.23: 0] length是0
複製程式碼

使用非負整數的字串或者一個跟整數相等的浮點數時,它就當做陣列的索引而非物件屬性。

let arr = [];
arr["100"] = 'a';
console.log(arr,arr.length) // arr 是[empty × 100, "a"],length 是101

let arr1 = [];
arr1[1.0000] = 'b';
console.log(arr1,arr1.length) // arr 是[empty, "b"],length 是2
複製程式碼

2、稀疏陣列

稀疏陣列就是包含從0開始的不連續索引的陣列。通常陣列的length屬性值代表陣列中元素的個數。如果陣列是稀疏的,length屬性值大於元素的個數

足夠稀疏的陣列通常在實現上比稠密的陣列更慢,更耗記憶體,在這樣的陣列中查詢元素所用的時間就變得跟常規物件的查詢時間一樣長了,失去了效能的優勢。

let a1 = [,,]; // 陣列直接量,該陣列是[empty × 2]
0 in a1 // false: a1在索引0處沒有元素

let a2 = new Array(3); //[empty × 3],該陣列根本沒有元素
0 in a2 // false: a2在索引0處沒有元素

let a3 = [undefined];
0 in a3 // true: a3在索引0處有一個值為undefined的元素

let a4 = [,undefined];
0 in a4 // fasle: a4在索引0處沒有元素
1 in a4 // true: a4在索引1處有一個值為undefined的元素
console.log(a4[0],a4[1]) // undefined undefined,可見陣列訪問返回undefined,可能是稀疏陣列,也可能是陣列元素為undefined
複製程式碼

3、類陣列物件

擁有一個數值length屬性和對應非負整數屬性的物件看做一種型別的陣列

陣列跟類陣列相比有以下不同:

  1. 當有新元素新增到陣列中時,自動更新length屬性
  2. 設定length為一個較小值將截斷陣列
  3. 從Array.prototype中繼承了一些方法
  4. 其類屬性為'Array'

JavaScript 陣列有很多方法特意定義通用,因此他們不僅應用在真正的陣列而且在類陣列物件上都能正確工作,JavaScript權威指南一書說的是:ES5中所有的方法都是通用的,ES3中除了toString()和toLocaleString()意外所有方法也是通用的。

類陣列物件顯然沒有繼承自Array.prototype,所以它們不能直接呼叫陣列方法,不過可以間接地使用Function.call方法呼叫。

// 類陣列應用通用方法
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
Array.prototype.join.call(arrayLike,'*') // "name*age*address"

// 還記得當初獲取的DOM元素怎麼轉化成陣列麼?
functon toArray (DOM) {
  return Array.prototype.slice.call(DOM);
}

//對的,這樣也可以的
let htmlCollection = document.getElementsByTagName('h2');
let arr1 = Array.prototype.map.call(htmlCollection,function (ele,index){return ele});
console.log(Array.isArray(arr1)) // true

// 還有這樣
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr2  = Array.prototype.concat.apply([],arrayLike);
console.log(arr) //["name", "age", "address"]

// ES6現在這樣
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr3 = Array.from(arrayLike);
console.log(arr3) // ["name", "age", "address"]
複製程式碼

4、 JavaScript陣列的進化——型別化陣列的引入

先說一下普遍意義上的Array,陣列是一串 連續 的記憶體位置,用來儲存某些值。JavaScript 中的陣列是雜湊對映,可以使用不同的資料結構來實現,如連結串列,上一個元素包含下一個元素的引用。這樣其他語言中陣列的取值是根據記憶體位置進行數學計算就能找到,而在JavaScript中就需要遍歷連結串列之類的結構,陣列越長,遍歷連結串列跟資料計算相比就越慢。

現代 JavaScript 引擎是會給陣列分配連續記憶體的 —— 如果陣列是同質的(所有元素型別相同)。所以在寫程式碼時保證陣列同質,以便 JIT(即時編譯器)能夠使用 c 編譯器式的計算方法讀取元素是一種優雅的方式。

不過,一旦你想要在某個同質陣列中插入一個其他型別的元素,JIT 將解構整個陣列,並按照舊有的方式重新建立。

ES6 增加了 ArrayBuffer, 提供一塊連續記憶體供我們隨意操作。然而,直接操作記憶體還是太複雜、偏底層。於是便有了處理 ArrayBuffer 的檢視(View)。

ArrayBuffer 物件用來表示通用的、固定長度的原始二進位制資料緩衝區。ArrayBuffer 不能直接操作,而是要通過型別陣列物件或 DataView 物件來操作,它們會將緩衝區中的資料表示為特定的格式,並通過這些格式來讀寫緩衝區的內容。

語法: new ArrayBuffer(length)

引數
length:要建立的 ArrayBuffer 的大小,單位為位元組。

返回值:一個指定大小的 ArrayBuffer 物件,其內容被初始化為 0。

異常:如果 length 大於 Number.MAX_SAFE_INTEGER(>= 2 ** 53)或為負數,則丟擲一個  RangeError  異常。
複製程式碼

型別陣列物件 一個TypedArray 物件描述一個底層的二進位制資料快取區的一個類似陣列(array-like)檢視。事實上,沒有名為 TypedArray的全域性物件,也沒有一個名為的 TypedArray建構函式。相反,有許多不同的全域性物件,下面會列出這些針對特定元素型別的型別化陣列的建構函式。

new TypedArray(); // ES2017中新增
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);

TypedArray()指的是以下的其中之一:

Int8Array();//8位二進位制帶符號整數 -2^7~(2^7) - 1,大小1個位元組
Uint8Array();//8位無符號整數 0~(2^8) - 1,大小1個位元組
Int16Array();//16位二進位制帶符號整數 -2^15~(2^15)-1,大小2個位元組
Uint16Array();//16位無符號整數 0~(2^16) - 1,大小2個位元組
Int32Array();//	32位二進位制帶符號整數 -2^31~(2^31)-1,大小4個位元組
Uint32Array();//32位無符號整數 0~(2^32) - 1,大小4個位元組
Float32Array();//32位IEEE浮點數,大小4個位元組
Float64Array(); //64位IEEE浮點數,大小8個位元組
複製程式碼

應用:

var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);
view[0] = 100;
console.log(view)// [100,0],一個八個位元組,Int32Array一個元素大小是4個位元組,所以只能放下兩個元素
複製程式碼

參考和連結

  1. 《JavaScript權威指南》陣列部分
  2. 詳解JS遍歷
  3. 給初學者:JavaScript 中陣列操作注意點
  4. 一次掌握 JavaScript ES5 到 ES8 陣列內容
  5. 【乾貨】js 陣列詳細操作方法及解析合集
  6. 【譯】 深入 JavaScript 陣列:進化與效能

其他

維護了一個持續更新的github筆記,可以去看看,誠意之作(本來就是寫給自己看的……)連結地址:Front-End-Basics

此篇文章的地址:JavaScript的陣列

基礎筆記的github地址:github.com/qiqihaobenb… ,可以watch,也可以star。

彩蛋

彩蛋就是關注奇舞週刊啊,文章寫得好,想讓更多人看到的同學,可以找我投稿啊。

JavaScript陣列的十八般武藝

相關文章