1. 程式人生 > 實用技巧 >JavaScript:陣列

JavaScript:陣列

1、建立陣列

// 推薦使用
var arr = [1, ,2 ,3];

// 不推薦使用
var arr = new Array(1, 2);

2、陣列的本質

本質上,陣列屬於一種特殊的物件。

typeof[1, 2, 3] // "Object"

陣列的特殊性體現在,它的鍵名是按次序排列的一組整數(0,1,2...)。

var arr = [1, 2, 3];

Object.keys(arr) //  ["0", "1", "2"]

3、陣列的遍歷

var arr = [1, 2, 3];
a.foo = true;

// for...in
for (var i in arr) {
    console.log(arr[i]); // 1 2 3 true
}

// for迴圈
for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]); // 1 2 3
}

// while迴圈
var i = 0; 
while(i < a.length) {
    console.log(arr[i]); // 1 2 3
    i++;
}

// forEach
arr.forEach(function (i) {
    console.log(i); // 1 2 3
});

使用for...in不僅會遍歷陣列所有的數字鍵,還會遍歷非數字鍵。所以,不推薦使用for...in遍歷陣列。

4、類似陣列的物件

如果一個物件的所有鍵名都是正整數或零,並且有length屬性,那麼這個物件就很像陣列,語法上稱為“類似陣列的物件”(array-like object)。

  • arguments物件

    function args() { return arguments }
    var arrayLike = args('a', 'b');
    
    arrayLike[0] // 'a'
    arrayLike.length // 2
    arrayLike instanceof Array // false
    
  • DOM元素集

    var elts = document.getElementsByTagName('h3');
    elts.length // 3
    elts instanceof Array // false
    
  • 字串

    'abc'[1] // 'b'
    'abc'.length // 3
    'abc' instanceof Array // false
    

5、建構函式

// 無引數時,返回一個空陣列
new Array() // []

// 單個正整數引數,表示返回的新陣列的長度
new Array(1) // [ empty ]
new Array(2) // [ empty x 2 ]

// 非正整數的數值作為引數,會報錯
new Array(3.2) // RangeError: Invalid array length
new Array(-3) // RangeError: Invalid array length

// 單個非數值(比如字串、布林值、物件等)作為引數,
// 則該引數是返回的新陣列的成員
new Array('abc') // ['abc']
new Array([1]) // [Array[1]]

// 多引數時,所有引數都是返回的新陣列的成員
new Array(1, 2) // [1, 2]
new Array('a', 'b', 'c') // ['a', 'b', 'c']

注意,如果引數是一個正整數,返回陣列的成員都是空位。雖然讀取的時候返回undefined,但實際上該位置沒有任何值。雖然這時可以讀取到length屬性,但是取不到鍵名。

var a = new Array(3);
var b = [undefined, undefined, undefined];

a.length // 3
b.length // 3

a[0] // undefined
b[0] // undefined

0 in a // false
0 in b // true

6、方法

  • Array.isArray():用來判斷某個變數是否是一個數組物件。

    var arr = [1, 2, 3];
    
    typeof arr // "object"
    Array.isArray(arr) // true
    
  • valueOf():返回陣列本身。

    Array.valueOf === Object.prototype.valueOf // true
    
    var arr = [1, 2, 3];
    arr.valueOf() // [1, 2, 3]
    
  • toString():返回陣列的字串形式。

    Array.toString === Function.prototype.toString // true
    
    var arr = [1, 2, 3];
    arr.toString() // "1,2,3"
    
    var arr = [1, 2, 3, [4, 5, 6]];
    arr.toString() // "1,2,3,4,5,6"
    
  • push():在陣列的末端新增一個或多個元素,並返回新增新元素後的陣列長度。注意,該方法會改變原陣列。

    var arr = [];
    
    arr.push(1) // 1
    arr.push('a') // 2
    arr.push(true, {}) // 4
    arr // [1, 'a', true, {}]
    
  • pop():刪除陣列的最後一個元素,並返回該元素。注意,該方法會改變原陣列。

    var arr = ['a', 'b', 'c'];
    
    arr.pop() // 'c'
    arr // ['a', 'b']
    
    [].pop() // undefined
    
  • shift():刪除陣列的第一個元素,並返回該元素。注意,該方法會改變原陣列。

    var a = ['a', 'b', 'c'];
    
    a.shift() // 'a'
    a // ['b', 'c']
    
    // 使用shift()遍歷陣列
    var arr = [1, 2, 3, 4];
    var i;
    
    while(i = arr.shift()) {
        console.log(i); // 1 2 3 4
    }
    
    arr // []
    
  • unshift():在陣列的第一個位置新增元素,並返回新增新元素後的陣列長度。注意,該方法會改變原陣列。

    var a = ['a', 'b', 'c'];
    
    a.unshift('x'); // 4
    a // ['x', 'a', 'b', 'c']
    
  • join():以指定引數作為分隔符,將所有陣列成員連線為一個字串返回。如果不提供引數,預設用逗號分隔。

    var a = [1, 2, 3, 4];
    
    a.join(' ') // '1 2 3 4'
    a.join(' | ') // "1 | 2 | 3 | 4"
    a.join() // "1,2,3,4"
    
    // 如果陣列成員是undefined或null或空位,會被轉成空字串。
    [undefined, null].join('#') // '#'
    
    ['a',, 'b'].join('-') // 'a--b'
    
  • concat():用於多個數組的合併。它將新陣列的成員,新增到原陣列成員的後部,然後返回一個新陣列,原陣列不變。

    ['hello'].concat(['world']) // ["hello", "world"]
    [1, 2, 3].concat(4, 5, 6) // [1, 2, 3, 4, 5, 6]
    

    如果陣列成員包括物件,concat方法返回當前陣列的一個淺拷貝。所謂“淺拷貝”,指的是新陣列拷貝的是物件的引用。

    var obj = { a: 1 };
    var oldArray = [obj];
    
    var newArray = oldArray.concat();
    
    obj.a = 2;
    newArray[0].a // 2
    
  • reverse():用於顛倒排列陣列元素,返回改變後的陣列。注意,該方法將改變原陣列。

    var a = ['a', 'b', 'c'];
    
    a.reverse() // ["c", "b", "a"]
    a // ["c", "b", "a"]
    
  • slice():用於提取目標陣列的一部分,返回一個新陣列,原陣列不變。

    arr.slice([begin[, end]])
    
    var a = ['a', 'b', 'c'];
    // 如果省略第二個引數,則一直返回到原陣列的最後一個成員。
    a.slice(0) // ["a", "b", "c"]
    a.slice(1) // ["b", "c"]
    // 包前不包後
    a.slice(1, 2) // ["b"]
    a.slice(2, 6) // ["c"]
    // 如果沒有引數,則返回原陣列的拷貝。
    a.slice() // ["a", "b", "c"]
    
    // 如果slice()方法的引數是負數,則表示倒數計算的位置。
    var a = ['a', 'b', 'c'];
    a.slice(-2) // ["b", "c"]
    a.slice(-2, -1) // ["b"]
    
    // 如果第一個引數大於等於陣列長度,或者第二個引數小於第一個引數,則返回空陣列。
    var a = ['a', 'b', 'c'];
    a.slice(4) // []
    a.slice(2, 1) // []
    

    slice()方法的一個重要應用,是將類似陣列的物件轉為真正的陣列。

    Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 }) // ['a', 'b']
    
    Array.prototype.slice.call(document.querySelectorAll("div"));
    Array.prototype.slice.call(arguments);
    
  • splice():用於刪除原陣列的一部分成員,並可以在刪除的位置新增新的陣列成員,返回值是被刪除的元素。注意,該方法會改變原陣列。

    array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
    
    var a = ['a', 'b', 'c', 'd', 'e', 'f'];
    a.splice(4, 2, 1, 2) // ["e", "f"]
    a // ["a", "b", "c", "d", 1, 2]
    
    // 如果只提供第一個引數,等同於將原陣列在指定位置拆分成兩個陣列。
    var a = [1, 2, 3, 4];
    a.splice(2) // [3, 4]
    a // [1, 2]
    
  • sort():對陣列成員進行排序,預設是按照字典順序排序。排序後,原陣列將被改變。

    ['d', 'c', 'b', 'a'].sort() // ['a', 'b', 'c', 'd']
    [4, 3, 2, 1].sort() // [1, 2, 3, 4]
    [11, 101].sort() // [101, 11]
    [10111, 1101, 111].sort() // [10111, 1101, 111]
    
    // 如果想讓sort方法按照自定義方式排序,可以傳入一個函式作為引數。
    [10111, 1101, 111].sort(function (a, b) {
      return a - b;
    })
    // [111, 1101, 10111]
    

    注意,自定義的排序函式應該返回數值,否則不同的瀏覽器可能有不同的實現,不能保證結果都一致。

    // bad
    [1, 4, 2, 6, 0, 6, 2, 6].sort((a, b) => a > b)
    
    // good
    [1, 4, 2, 6, 0, 6, 2, 6].sort((a, b) => a - b)
    
  • map():將陣列的所有成員依次傳入引數函式,然後把每一次的執行結果組成一個新陣列返回。

    var new_array = arr.map(function callback(currentValue[, index[, array]]) {
     // Return element for new_array 
    }[, thisArg])
    // 回撥函式有三個引數,currentValue為當前成員的值,index為當前成員的位置,array為原陣列
    // thisArg用來繫結回撥函式內部的this變數
    
  • forEach():對陣列的每個元素執行一次給定的函式,沒有返回值。

    arr.forEach(function callback(currentValue [, index [, array]])[, thisArg])
    // forEach()的引數與map()相同
    // forEach()不會跳過undefined和null,但會跳過空位。
    
  • filter():用於過濾陣列成員,滿足條件的成員組成一個新陣列返回。

    var newArray = arr.filter(function callback(element[, index[, array]])[, thisArg])
    // 回撥函式有三個引數,element為當前成員,index為當前成員的位置,array為原陣列
    // thisArg用來繫結回撥函式內部的this變數
    
  • some():只要一個成員的返回值是true,則整個some方法的返回值就是true,否則返回false

    arr.some(function callback(element[, index[, array]])[, thisArg])
    // 回撥函式有三個引數,element為當前成員,index為當前成員的位置,array為原陣列
    // thisArg用來繫結回撥函式內部的this變數
    
  • every():所有成員的返回值都是true,整個every方法才返回true,否則返回false

    arr.every(function callback(element[, index[, array]])[, thisArg])
    // 回撥函式有三個引數,element為當前成員,index為當前成員的位置,array為原陣列
    // thisArg用來繫結回撥函式內部的this變數
    
  • reduce():從左到右依次處理陣列的每個成員,最終累計為一個值。

    arr.reduce(function callback(accumulator, currentValue[, index[, array]])[, initialValue])
    // accumulator累積變數,currentValue當前變數,index當前位置,array原陣列,initialValue累積變數初始值
    
    // 找出字元長度最長的陣列成員。
    function findLongest(entries) {
      return entries.reduce(function (longest, entry) {
        return entry.length > longest.length ? entry : longest;
      }, '');
    }
    
    findLongest(['aaa', 'bb', 'c']) // "aaa"
    
  • reduceRight():從右到左依次處理陣列的每個成員,最終累計為一個值。

    arr.reduceRight(function callback(accumulator, currentValue[, index[, array]])[, initialValue])
    // accumulator累積變數,currentValue當前變數,index當前位置,array原陣列,initialValue累積變數初始值
    // 在空陣列上呼叫 reduce 或 reduceRight 且未提供初始值會導致型別錯誤
    
  • indexOf():返回給定元素在陣列中第一次出現的位置,如果沒有出現則返回-1

    arr.indexOf(searchElement[, fromIndex])
    // searchElement要查詢的元素,fromIndex開始查詢的位置
    
    [NaN].indexOf(NaN) // -1
    
  • lastIndexOf():返回給定元素在陣列中最後一次出現的位置,如果沒有出現則返回-1

    arr.lastIndexOf(searchElement[, fromIndex])
    // searchElement要查詢的元素,fromIndex開始查詢的位置
    
    [NaN].lastIndexOf(NaN) // -1
    
  • 鏈式使用:上面這些陣列方法之中,有不少返回的還是陣列,所以可以鏈式使用。

    var users = [
      {name: 'tom', email: '[email protected]'},
      {name: 'peter', email: '[email protected]'}
    ];
    
    users
    .map(function (user) {
      return user.email;
    })
    .filter(function (email) {
      return /^t/.test(email);
    })
    .forEach(function (email) {
      console.log(email);
    });
    // "[email protected]"
    

    上面程式碼中,先產生一個所有 Email 地址組成的陣列,然後再過濾出以t開頭的 Email 地址,最後將它打印出來。

7、參考資料