1. 程式人生 > 實用技巧 >【深度長文】JavaScript陣列所有API全解密

【深度長文】JavaScript陣列所有API全解密

目錄

此文轉載自louis blog

本文先佔坑,主要是想總結一下知識點,鞏固自己的基礎,程式碼都會自己本地先跑通,也會加上一些自己的理解和補充

陣列是一種非常重要的資料型別,語法簡單、靈活、高效。在多數程式語言中,陣列都充當著至關重要的角色,以至於很難想象沒有陣列的程式語言會是什麼模樣。特別是JavaScript,
它天生的靈活性,又進一步發揮了陣列的特長,豐富了陣列的使用場景。可以豪不誇張地說,不深入地瞭解陣列,不足以寫JavaScript。

截止ES7規範,陣列共包含33個標準的API方法和一個非標準的API方法,使用場景和使用方案紛繁複雜,其中有不少淺坑、深坑、甚至神坑。下面將從Array構造器及ES6新特性開始,逐步幫助你掌握陣列。

Array建構函式

Array構造器用於創造一個新的陣列。通常,我們推薦使用物件字面量建立陣列,這是一個好習慣,但是總有物件字面量乏力的時候,
比如我想建立一個長度為8的空陣列,請看下面兩種方式

// 使用Array構造器
let a = Array(8); // [ <8 empty items> ]

// 使用物件字面量
let b = [];
b.length = 8; // [ <8 empty items> ]

Array構造器明顯要簡潔一些。

如上,我使用了Array(8),而不是new Array(8),這會有影響嗎?實際上並沒有影響,這得益於Array構造器內部對this指標的判斷,規範內部做了如下處理

When Array is called as a function rather than as a constructor, it creates and initialises a new Array object. Thus the function call Array(…) is
equivalent to the object creation expression new Array(…) with the same arguments.

翻譯一下

當將Array呼叫為函式而不是建構函式時,它將建立並初始化一個新的Array物件。 因此,函式呼叫Array(…)等效於具有相同引數的物件建立表示式new Array(…)。

function Array(){
  // 如果this不是Array的例項,那就重新new一個例項
  if(!(this instanceof arguments.callee)){
    return new arguments.callee();
  }
}

下面介紹Array建構函式的介紹,建構函式根據引數長度的不同,有如下兩種不同的處理:

  • new Array(arg1,arg2,...),引數長度為0時,返回空陣列,長度大於等於2時,傳入的引數將按照順序依次成為新陣列的第0-N項。
let a = Array(); // []

let b = Array(1,2,3) // []
  • new Array(len),當len不是數值時,處理同上,返回一個只包含len元素一項的陣列;當len為數值時,根據如下規範,len最大不能超過32位無符號整型,
    即需要小於2的32次方(len最大為Math.pow(2,32)-1-1>>>0),否則將丟擲RangeError。

If the argument len is a Number and ToUint32(len) is equal to len, then the length property of the newly constructed object is set to ToUint32(len).
If the argument len is a Number and ToUint32(len) is not equal to len, a RangeError exception is thrown.

翻譯一下:

如果引數len是Number並且ToUint32(len)等於len,則新構造物件的length屬性將設定為ToUint32(len)。 如果引數len是Number並且ToUint32(len)不等於len,則會引發RangeError異常。

let a = Array('hello');   // ['hello']

let b = Array(3);         // [<3 empty items>]

let c = Array(Math.pow(2,32))  // RangeError: Invalid array length
let d = Array(-1 >>> 0)        // RangeError: Invalid array length

這裡補充一個js右移>>>的知識點,可以參考js >>> 0 談談 js 中的位運算
或者MDN按位操作符學習一下

以上,請注意Array構造器對於單個數值引數的特殊處理,如果僅僅需要使用陣列包裹?若干引數,不妨試試使用Array.of

ES6新增的建構函式方法

鑑於陣列的常用性,ES6專門擴充套件了陣列構造器Array,新增了兩個方法: Array.of,Array.from。下面看看怎麼使用

Array.of

Array.of用於將引數依次轉化為陣列中的一項,然後返回這個新陣列,而不管這個引數是數字還是其它。它基本上與Array構造器功能一致,唯一的區別就在單個數字引數的處理上。如下:

Array.of(8.0); // [8]
Array(8.0); // [empty × 8]

引數為多個,或單個引數不是數字時,Array.of 與 Array構造器等同。

Array.of(8.0, 5); // [8, 5]
Array(8.0, 5); // [8, 5]

Array.of('8'); // ["8"]
Array('8'); // ["8"]

因此,若是需要使用陣列包裹元素,推薦優先使用Array.of方法。

目前,以下版本瀏覽器提供了對Array.of的支援。

Chrome Firefox Edge Safari
45+ 25+ ✔️ 9.0+

即使其他版本瀏覽器不支援也不必擔心,由於Array.of與Array構造器的這種高度相似性,實現一個polyfill十分簡單。如下:

if (!Array.of){
  Array.of = function(){
    return Array.prototype.slice.call(arguments);
  };
}