細說JS數組

此乃犀牛書(第七章 數組)讀書筆記,又結合了ES6中數組的擴展部分作的知識梳理。
精華部分就是手工繪製的兩張數組總結圖了。
靈活運用數組的各類方法是基本功,是基本功,是基本功,重要的事情說三遍。
好了,正文從下面開始~數組

數組的基本概念

什麼是數組,數組元素,數組索引

對象是屬性的無序集合,而數組是值的有序集合;
每一個值叫作一個元素,每一個元素在數組中的位置稱爲索引;函數

JS數組有什麼特色

  • JS數組是無類型的:數組元素能夠是任意類型,同一個數組中的元素也可能有不一樣類型;優化

  • JS數組是動態的:可根據須要增加或縮減;spa

  • JS數組多是稀疏的:數組元素的索引不必定是連續的。prototype

稀疏數組

  • 稀疏數組length屬性值大於元素的個數code

  • 建立稀疏數組的兩種方法:對象

var a= []; a[1000] =1  //直接量
var a = [1,2,3,4,5,6]; delete a[0];  //刪除從而使得不連續

數組對象和普通對象的聯繫和區別?

  • 數組是特殊的對象,使用[]訪問數組元素就像使用[]訪問對象屬性同樣(索引就是屬性名)blog

  • 數組的特別之處在於,當使用小於2的32次方的非負整數做爲屬性名時數組會自動維持其length屬性值,length屬性使得數組區別於常規JS對象。索引

當爲數組元素賦值時,索引i大於或等於length,length屬性變爲i+1;
當設置數組length屬性小於當前數組長度時,大於的部分將被刪除;
也能夠設置數組的length屬性大於當前數組長度,這時後面會建立空區域;
可使用Object.defineProperty()將數組length屬性設置爲只讀的。rem

  • 如何判斷一個對象是數組對象?

    • ES5提供了一個方法:

      Array.isArray(a)    // true or false
    • 還能夠經過檢查對象的類屬性(class)

    Object.prototype.toString.call(a) == '[object array]'
    //這裏須要使用Object的toString方法,由於Array的toString方法被重寫了。

注意:使用instanceof判斷數組對象是不靠譜的。這是由於當跨越多個窗體時,檢測會失敗。

類數組對象

  • 類數組對象:擁有length屬性,屬性是非負整數的對象

  • 數組方法在類數組對象上也能work, 類數組對象不能直接調用數組的方法,但能夠間接調用

  • 常見的類數組對象:arguments對象、一些DOM方法的返回

數組的操做(建立、讀寫、添加、刪除、遍歷)及方法

下面用一張圖來總結一下數組的方法:

按照標準演進分數組方法.png

這張圖是按照ES標準發展的順序總結了標準中數組提供的方法,畫完圖的我表示嚇了一跳。ES6居然提供了這麼多新的方法。看來使用的是至關不充分。之後要考慮少用underscore了。。。

上圖中每一個方法可能能夠實現不止一種功能(例如splice既能實現爲數組增長元素,又能刪除數組元素),那麼按照數組操做劃分,這張圖又能夠變成下面這個樣子:

按照數組元素操做劃分數組的方法.png

下面對上述兩張圖裏面的部分知識進行詳細說明和demo演示。

建立數組的三種方法

  • 數組直接量

var a = [1, true,'hi'];
var b = [,,]  //undefined*2
  • new + Array

var a = new Array()
var b = new Array(10)
var c = new Array(1,2)
  • Array.of()

Array.of(1,2,3)  //[1,2,3]

這是ES6中提供的方法,爲了彌補new+Array在傳入不一樣個數的參數時輸出不一致的問題。

數組元素的讀寫:[]

使用'[]'訪問數組元素時,js將索引轉換爲字符串,而後將其做爲屬性名同樣使用。

//注意使用負整數和浮點數做爲索引時:
a[-123]   //同a['-123']
a[1.000]  //同a[1]

爲數組添加元素有至少下面這麼多辦法:

var a = [];
a[1] = 1; 
a.push(1)
a.unshift(1)  //以上都使得a變成了[1]

delete刪除數組元素不改變length

delete刪除數組元素是不改變數組的length的,也不會讓其餘數組元素索引起生改變,會讓數組變爲稀疏數組。

遍歷數組元素有什麼方法?

最簡單的方案就是使用for循環,那麼,使用for循環遍歷數組時能夠有哪些優化點?

首先,若是數組不是稠密的,應該加判斷排除null, undefined和不存在的元素,以免多餘循環;

其次,數組長度應該先求出來,而非每次循環都去查詢長度,可是這種適用於在遍歷過程當中不修改數組長度的狀況(試一下一邊遍歷,一邊刪除數組元素的狀況);

使用for循環和使用forEach,map這些方法有什麼區別?

使用for循環,能夠從後向前遍歷數組,而使用方法則作不到。

sort方法不可不知

sort() 直接使用時是按照字母順序排列的。若是想要根據數值大小順序排列,能夠在回調函數裏指定。

var a= [33,4,1111,222]
a.sort()  //[1111,222,33,4]
a.sort((a,b)=>{
  return a-b  //<0  第一個參數應該在前
}) //[4,33,222,1111]

concat()只展開一層數組元素

var a = [1,2,3]
var b = a.concat(4,5) //a不變,返回[1,2,3,4,5]

注意,concat只拼接第一層結構。
另外,使用擴展運算符一樣能實現數組拼接:

var a = [1,2,3]
var b = [...a,4,5]

厲害的splice()

splice既能刪除元素,也能插入元素,取決於有咩有第三個參數
splice是修改數組自己的,可是slice方法是不修改數組自己的。

var a = [1,2,3,4,5,6]
a.splice(4)   //a: [1,2,3,4]
a.splice(2,1) //[1,2,4]
a.splice(2,1,3)  //[1,2,3]

ES5數組的方法都有的一些特色

ES5數組方法的特色:

  • 第一個參數是函數,對數組的每一個元素調用一次該函數

  • 若是是稀疏數組,對不存在的元素不調用傳遞的函數(wow)

  • 不修改原始數組

forEach方法

forEach 不能break , 想break 須要try catch
forEach不修改原始數組,想修改,能夠藉助第三個參數

var data = [1,2,3,4,5,6]
data.forEach((ele, index, dd)=>{
  dd[index] = ele + 1
})
//data: [2,3,4,5,6,7]

map 一般都須要一個return:

map方法也不修改原始數組

var b = a.map(function(ele){return ele+1})

indexOf()與includes()方法的比較

indexOf方法有兩個缺點:

  • 不夠語義化,它的含義是找到參數值出現的第一個位置,因此要去比較是否不等於-1

  • 內部使用嚴格運算符'===',因此會致使對NaN的誤判

    [NaN].indexOf(NaN)   //-1

而includes方法沒有這個問題。

[NaN].includes(NaN)   //true

關於數組的方法衆多,在使用時多嘗試不一樣的方法,方能熟記各種方法的特色。

未完待續~

相關文章
相關標籤/搜索