1. 程式人生 > >JavaScript 整理筆記之陣列詳解

JavaScript 整理筆記之陣列詳解

JavaScript 資料型別之陣列 Array

1.定義

Array 物件用於在單個的變數中儲存多個值。
typeof [] === 'object'; // true
Object.keys([1, 3, 5, 7]); // [0, 1, 2, 3] 返回陣列物件的key值陣列

2.建立方法

var arr1 = new Array(); // []
var arr2 = new Array(3); // [undefined x 3]
var arr3 = new Array(1, 2, 3); // [1, 2, 3]
var arr4 = []; // []

3.屬性

length屬性 - 設定或返回陣列中元素的數目。

arr1.length; // 0
arr2.length; // 0
arr3.length; // 3
arr4.length; // 0
JavaScript語言規定,物件的鍵名一律為字串,所以,陣列的鍵名其實也是字串。之所以可以用數值讀取,是因為非字串的鍵名會被轉為字串。
arr3["1"]; // 2
arr3[1]; // 2
length屬性是可寫的。如果人為設定一個小於當前成員個數的值,該陣列的成員會自動減少到length設定的值。
arr3.length = 2;
arr3; // [1, 2]

constructor屬性 - 返回對建立此物件的陣列函式的引用。

arr1.constructor; // ƒ Array() { [native code] }

prototype屬性 - 使您有能力向物件新增屬性和方法。

Array.prototype.empty = function(){
	return [];
};
[1, 2, 3, 4].empty(); // []

4.類似陣列的物件

函式的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.方法

Array.isArray() - 該方法判斷是否是陣列

var arr = [];
Array.isArray(arr); // true

valueOf() - 該方法返回陣列本身。

var arr = [1, 2, 3];
arr.valueOf(); // [1, 2, 3]

toString() - 該方法返回陣列的字串形式。

var arr = [1, 2, 3];
arr.toString(); // '1,2,3'

push() - 該方法用於在陣列的末端新增一個或多個元素,並返回新增新元素後的陣列長度。注意,該方法會改變原陣列。

var arr = [1, 2, 3];
arr.push(5); // 4
arr; // [1, 2, 3, 5]
arr.push(4, 5); // 6
arr; // [1, 2, 3, 5, 4, 5]
如果需要合併兩個陣列,可以這樣寫。
var arr2 = [5, 6, 7];
arr.push.apply(arr, arr2); // 9 此時返回的是陣列改變後的長度
arr; // [1, 2, 3, 5, 4, 5, 5, 6, 7]
push方法還可以用於向物件新增元素,新增後的物件變成類似陣列的物件,即新加入元素的鍵對應陣列的索引,並且物件有一個length屬性。
var obj = { a: 1 };
[].push.call(obj, 1); // 1 
obj; // {a: 1, 0: 1, length: 1}
[].push.call(obj, 2); // 2
obj; // {a: 1, 0: 1, 1: 2, length: 2}

pop() - 該方法用於刪除陣列的最後一個元素,並返回該元素。注意,該方法會改變原陣列。

var arr = [1, 3, 5];
arr.pop(); // 5
arr; // [1, 3]
對空陣列使用pop方法,不會報錯,而是返回undefined。
[].pop(); // undefined

join() - 該方法以引數作為分隔符,將所有陣列成員組成一個字串返回。如果不提供引數,預設用逗號分隔。

var arr = ['j', 'o', 'i', 'n'];
arr.join(); // 'j,o,i,n'
arr.join(''); // 'join'
如果陣列成員是undefined或null或空位,會被轉成空字串。
var arr = [undefined, null, , ''];
arr.jooin('#'); // ###
通過call方法,這個方法也可以用於字串。
Array.prototype.join.call("hello", "-"); // 'h-e-l-l-o'
join方法也可以用於類似陣列的物件。
Array.prototype.join.call(arrayLike, "-"); // 'a-b'

concat() - 該方法用於多個數組的合併。它將新陣列的成員,新增到原陣列的尾部,然後返回一個新陣列,原陣列不變。

var arr = [1, 3];
arr.concat([2,4]); // [1, 3, 2, 4]
arr; // [1, 3]
[1, 2].concat([3, 4], [5, 6]); // [1,2,3,4,5,6]
除了接受陣列作為引數,concat也可以接受其他型別的值作為引數。它們會作為新的元素,新增陣列尾部。
[1, 2].concat(4, 5, 6); // [1, 2, 4, 5, 6]
concat方法也可以用於將物件合併為陣列,但是必須藉助call方法。
[].concat.call({ 1: 2 }, { 2: 3 }); // [{1;2},{2:3}]
[2].concat({ 1: 2 }); // [2,{1;2}]
[].concat.call({ 1: 2 }, [2]); // [{1;2},2]

shift() - 該方法用於刪除陣列的第一個元素,並返回該元素。注意,該方法會改變原陣列。

var arr = [1, 3];
arr.shift(); // 1
arr; // [3]
[].shift(); // undefined

unshift() - 該方法用於在陣列的第一個位置新增元素,並返回新增新元素後的陣列長度。注意,該方法會改變原陣列。

var arr = [2, 3, 4, 5];
arr.unshift(1); // 5
arr; // [1, 2, 3, 4, 5]

reverse() - 方法用於顛倒陣列中元素的順序,返回改變後的陣列。注意,該方法將改變原陣列。

var arr = [1, 3, 5];
arr.reverse(); // [5, 3, 1]

slice() - 該方法用於提取原陣列的一部分,返回一個新陣列,原陣列不變。

var arr = [2, 4, 6, 8, 10];
arr.slice(2); // [6, 8, 10]
arr.slice(0, 1); // [2]
arr.slice(-1); // [10]	相當於 arr.slice(-1 + arr.length) => arr.slice(4)
arr.slice(-3, -1); // [6, 8] 相當於 arr.slice(-3 + arr.length, -1 + arr.length) => arr.slice(2, 4)
arr; //  [2, 4, 6, 8, 10]
slice方法的一個重要應用,是將類似陣列的物件轉為真正的陣列。
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 }); // ['a', 'b']
Array.prototype.slice.call(document.querySelectorAll("div")); // [div, div, div]
function args2(){
	return Array.prototype.slice.call(arguments);
}
args2(1, 2, 3); // [1, 2, 3]

splice() - 該方法用於刪除原陣列的一部分成員,並可以在被刪除的位置新增入新的陣列成員,返回值是被刪除的元素。注意,該方法會改變原陣列。 splice的第一個引數是刪除的起始位置,第二個引數是被刪除的元素個數。如果後面還有更多的引數,則表示這些就是要被插入陣列的新元素。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.splice(8); // [9]
arr; // [1, 2, 3, 4, 5, 6, 7, 8]
arr.splice(5, 2); // [6, 7]
arr; // [1, 2, 3, 4, 5, 8]
arr.splice(-2, 2, 1, 2, 3); // [5, 8]
arr; // [1, 2, 3, 4, 1, 2, 3]

sort() - 方法對陣列成員進行排序,預設是按照字典順序排序。排序後,原陣列將被改變。

var arr = [5, 2, 3];
arr.sort(); // [2, 3, 5]
arr; // [2, 3, 5]
sort方法不是按照大小排序,而是按照對應字串的字典順序排序。也就是說,數值會被先轉成字串,再按照字典順序進行比較,所以101排在11的前面。
[101, 11].sort(); // [101, 11]
[101, 11].sort(function(a, b){
	return a - b;
}); // [11, 101]
[101, 11].sort(function(a, b){
	return a - b <= 0;
}); // [101, 11]

map() - 該方法對陣列的所有成員依次呼叫一個函式,根據函式結果返回一個新陣列, 原陣列沒有變化。

 var arr = [1, 3, 5];
 arr.map(function(v) {
    return v * v;
}); // [1, 9, 25]
arr; // [1, 3, 5]
map方法接受一個函式作為引數。該函式呼叫時,map方法會將其傳入三個引數,分別是當前成員、當前位置和陣列本身。
 arr.map(function(value, index, arr) {
    return index;
}); // [0, 1, 2]
map方法不僅可以用於陣列,還可以用於字串,用來遍歷字串的每個字元。但是,不能直接使用,而要通過函式的call方法間接使用,或者先將字串轉為陣列,然後使用。
Array.prototype.map.call("hello", (function(v) {
    return v.toUpperCase();
})); // ["H", "E", "L", "L", "O"]
map方法還可以接受第二個引數,表示回撥函式執行時this所指向的物件。
var arr = [5, 6, 7, 8];
[1, 2, 3].map(function(v) {
    return this[v];
}, arr); // [6, 7, 8]
如果陣列有空位,map方法的回撥函式在這個位置不會執行,會跳過陣列的空位, undefined和null不會跳過。
var f = function(n) { return n + 1 };
[1, undefined, 3].map(f); // [2, NaN, 4]
[1, null, 3].map(f); // [2, 1, 4]
[1, , 3].map(f); // [2, , 4]

forEach() - 該方法與map方法很相似,也是遍歷陣列的所有成員,執行某種操作,但是forEach方法一般不返回值,只用來操作資料。如果需要有返回值,一般使用map方法。forEach方法的引數與map方法一致,也是一個函式,陣列的所有成員會依次執行該函式。它接受三個引數,分別是當前位置的值、當前位置的編號和整個陣列。

[1, 2, 3].forEach(function(value, index, arr) {
    console.log("[" + index + "] = " + value);
}); 
// [0] = 1 [1] = 2 [2] = 3 
forEach方法也可以接受第二個引數,用來繫結回撥函式的this關鍵字。
var arr = [];
[1, 2, 3, 4].forEach(function(v) {
    this.push(v * v);
}, arr);
arr; // [1, 4, 9, 16]
固定this
var obj2 = {
    0: 1,
    1: 2,
    name: ["stafan", "cindy", "xichen"],
    index: [1, 2, 3],
    print: function() {
        this.index.forEach(function(v) {
            console.log("thisName => ", this.name[v - 1]);
        }, this); // this 指向 obj2
    }
}
obj2.print(); // "thisName => stafan"    "thisName => cindy"   "thisName => xichen"
注意,forEach方法無法中斷執行,總是會將所有成員遍歷完。如果希望符合某種條件時,就中斷遍歷,要使用for迴圈。forEach方法會跳過陣列的空位。
function log(n) {
    console.log(n + 1);
}
[1, undefined, 2].forEach(log); // 2,NaN,3
[1, null, 2].forEach(log); // 2,1,3
[1, , 2].forEach(log); // 2,3
forEach方法也可以用於類似陣列的物件和字串。
var obj3 = {
    0: 1,
    1.: 2,
    length: 2
}
Array.prototype.forEach.call(obj3, function(value, index, arr) {
    console.log(index + ':' + value);
}); // 0:1  1:2
var str2 = 'hello';
Array.prototype.forEach.call(str2, function(value, index, arr) {
    console.log(index + ':' + value);
}); // 0:h 1:e 2:l 3:l 4:o

filter() - 該方法的引數是一個函式,所有陣列成員依次執行該函式,返回結果為true的成員組成一個新陣列返回。該方法不會改變原陣列。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.filter(function(value, index, arr) {
    return value % 2 === 0;
})); // [2, 4, 6, 8]
arr; // [1,2,3,4,5,6,7,8,9]
filter方法還可以接受第二個引數,指定測試函式所在的上下文物件(即this物件)
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.filter(function(value, index, arr) {
    return this.MAX > value;
}, {  MAX: 3 }); // [1, 2]

some() - 該方法是隻要有一個數組成員的返回值是true,則整個some方法的返回值就是true,否則false。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.some(function(value, index, arr){
	return value > 8;
}); // true
[3, 4, 5].some(function(value, index, arr) {
    return value > 5;
}); // false

every() - 該方法則是所有陣列成員的返回值都是true,才返回true,否則false。

[3, 4, 5].every(function(value, index, arr) {
    return value > 2;
}); // true
[3, 4, 5].every(function(value, index, arr) {
    return value > 4;
}); // false
注意,對於空陣列,some方法返回false,every方法返回true,回撥函式都不會執行。
[].some(log); // false
[].every(log); // true

reduce方法和reduceRight方法依次處理陣列的每個成員,最終累計為一個值。

它們的差別是, reduce是從左到右處理( 從第一個成員到最後一個成員), reduceRight則是從右到左( 從最後一個成員到第一個成員), 其他完全一樣。
 這兩個方法的第一個引數都是一個函式。 該函式接受以下四個引數。
累積變數, 預設為陣列的第一個成員
當前變數, 預設為陣列的第二個成員
當前位置( 從0開始)
原陣列
這四個引數之中, 只有前兩個是必須的, 後兩個則是可選的。
[1, 2, 3, 4, 5].reduce(function(x, y, i, arr) {
    return x + y;
}); // 15
如果要對累積變數指定初值,可以把它放在reduce方法和reduceRight方法的第二個引數。
[1, 2, 3, 4, 5].reduce(function(x, y, i, arr) {
    console.log(x, y, i, arr);
    return x + y;
}, 10); // 25 第二個參引數相當於指定 x 的初始值
由於空陣列取不到初始值,reduce方法會報錯。這時,加上第二個引數,就能保證總是會返回一個值。
var sum = function(x, y) {
    return x + y;
};
[].reduce(sum, 0); // 0
[].reduce(sum); // TypeError: Reduce of empty array with no initial value 
var subtract = function(x, y) {
    return x - y;
}
[3, 2, 1].reduce(subtract); // 0
[3, 2, 1].reduceRight(subtract); // -4
reduce 變相找出長度最長的元素
function findLongest(entries) {
    return entries.reduce(function(x, y, i, arr) {
        return x.length > y.length ? x : y;
    }, '');
}
findLongest(['ss', 'abc', 'stafan', 'cindy']); // stafan

indexOf() - 該方法返回給定元素在陣列中第一次出現的位置,如果沒有出現則返回-1。

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

lastIndexOf() - 該方法返回給定元素在陣列中最後一次出現的位置,如果沒有出現則返回-1。

[1, 2, 3, 1].lastIndexOf(1); // 3
[1, 2, 3, 1].lastIndexOf(4); // -1
// 注意,如果陣列中包含NaN,這兩個方法不適用,即無法確定陣列成員是否包含NaN。
[NaN].indexOf(NaN); // -1
[NaN].lastIndexOf(NaN); // -1
上面這些陣列方法之中,有不少返回的還是陣列,所以可以鏈式使用。
var users = [
    { name: 'tom', email: '[email protected]' },
    { name: 'peter', email: '[email protected]' },
    { name: 'peter', email: '[email protected]' },
];
users
    .map(function(user) {
        return user.email;
    })
    .filter(function(email) {
        return /^t/.test(email);
    })
    .forEach(function(v){
        console.log(v);
    });