2 Array類型
2.0.1 創建方式
- 第一種是使用
Array 構造函數
let colors = new Array(); //創建一個空數組
let colors = new Array(20); //創建length值為20的空數組
let colors = new Array("red"); //創建length值為1的非空數組
let colors = Array(3); //可以省略new操作符,然后情況跟new Array()使用方式相同
- 第二種基本方式是使用
數組字面量表示法
let colors = ["red", "blue", "green"]; // 創建一個包含3 個字符串的數組
let names = []; // 創建一個空數組
let values = [1,2,]; // 不要這樣!這樣會創建一個包含2 或3 項的數組
let options = [,,,,,]; // 不要這樣!這樣會創建一個包含5 或6 項的數組
具體原因說一下:因為IE8 及之前版本中的ECMAScript 實現在數組字面量方面存在bug。IE8及更早的版本,可能會創建6項;在IE9+、Firefox、Opera、Safari 和Chrome 中可能會創建5項。在像這種省略值的情況下,每一項都將獲得undefined 值;這個結果與調用Array 構造函數時傳遞項數在邏輯上是相同的。但是由于IE 的實現與其他瀏覽器不一致,因此我們強烈建議不要使用這種語法。
2.1檢測數組
- instanceof(適用于只有一個全局作用域)
if (value instanceof Array){
//對數組執行某些操作
};
instanceof 操作符的問題在于,它假定只有一個全局執行環境。如果網頁中包含多個框架,那實際上就存在兩個以上不同的全局執行環境,從而存在兩個以上不同版本的Array 構造函數,從而產生錯誤檢測結果。
- Array.isArray()
if (Array.isArray(value)){
//對數組執行某些操作
};
支持Array.isArray()方法的瀏覽器有IE9+、Firefox 4+、Safari 5+、Opera 10.5+和Chrome。
然后:
由于兩種方法都有各自的局限性,要在尚未實現這個方法中的瀏覽器中準確檢測數組,不妨采用下面提供的方法
- 使用Object.prototype上的原生toString()方法判斷數據類型
大家知道,在任何值上調用Object 原生的
toString()
方法,都會返回一個
[object NativeConstructorName]
格式的字符串。每個類在內部都有一個[[Class]]
屬性,這個屬性中就指定了上述字符串中的構造函數名。舉個例子吧。
alert(Object.prototype.toString.call(value)); //"[object Array]"
由于原生數組的構造函數名與全局作用域無關,因此使用
toString()
就能保證返回一致的值。利用這一點,可以創建如下函數:
function isArray(value){
return Object.prototype.toString.call(value) == "[object Array]";
}
同樣,也可以基于這一思路來測試某個值是不是原生函數或正則表達式(擴展一下):
function isFunction(value){
return Object.prototype.toString.call(value) == "[object Function]";
}
function isRegExp(value){
return Object.prototype.toString.call(value) == "[object RegExp]";
}
不過要注意,對于在IE 中以COM 對象形式實現的任何函數,isFunction()都將返回false(因為它們并非原生的JavaScript 函數)
這一技巧也廣泛應用于檢測原生JSON 對象。Object 的toString()
方法不能檢測非原生構造函數的構造函數名。因此,開發人員定義的任何構造函數都將返回[object Object]
。有些JavaScript 庫會包含與下面類似的代碼。
let isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) == "[object JSON]";
在Web 開發中能夠區分原生與非原生JavaScript 對象非常重要。只有這樣才能確切知道某個對象到底有哪些功能。這個技巧可以對任何對象給出正確的結論。
請注意,Object.prototpye.toString()
本身也可能會被修改。本節討論的
技巧假設Object.prototpye.toString()
是未被修改過的原生版本。
2.2轉換方法
如前所述,所有對象都具有toLocaleString()、toString()和valueOf()方法。
let colors = ["red", "blue", "green"]; // 創建一個包含3 個字符串的數組
alert(colors.toString()); // "red,blue,green"
alert(colors.valueOf()); // [red,blue,green]
alert(colors.toLocalString()); // "red,blue,green"
alert(colors.join("||")); //"red||green||blue"
先拋出這么多,join方法還是挺有用的。
2.3棧方法 (LIFO:Last-In-First-Out,后進先出)
push方法是像數組末端添加項,返回的是數組長度;pop方法返回的是取出的最后一項;
let colors = new Array(); // 創建一個數組
let count = colors.push("red", "green"); // 推入兩項
alert(count); //2
count = colors.push("black"); // 推入另一項
alert(count); //3
let item = colors.pop(); // 取得最后一項
alert(item); //"black"
alert(colors.length); //2
colors[colors.length] = "yellow"; // 賦值最后一項,功能類似push();
alert(colors); //["red", "green", "yellow"]
2.4隊列方法 (FIFO:First-In-First-Out,先進先出)
實現這一操作的數組方法就是shift(),它能夠移除數組中的第一個項并返回該項,同時將數組長度減1。結合使用shift()和push()方法,可以像使用隊列一樣使用數組。
let colors = new Array(); //創建一個數組
let count = colors.push("red", "green"); //推入兩項
alert(count); //2
count = colors.push("black"); //推入另一項
alert(count); //3
let item = colors.shift(); //取得第一項
alert(item); //"red"
alert(colors.length); //2
同時使用unshift()和pop()方法,可以從相反的方向來模擬隊列,即在數組的前端添加項,從數組末端移除項。
let colors = new Array(); //創建一個數組
let count = colors.unshift("red", "green"); //推入兩項
alert(count); //2
count = colors.unshift("black"); //推入另一項
alert(count); //3
elt item = colors.pop(); //取得最后一項
alert(item); //"green"
alert(colors.length); //2
tips:IE7 及更早版本對JavaScript 的實現中存在一個偏差,其unshift()方法總是返回undefined 而不是數組的新長度。IE8 在非兼容模式下會返回正確的長度值。
2.5 重排序方法
數組中已經存在兩個可以直接用來重排序的方法:reverse()和sort()。
let values = [1, 2, 3, 4, 5];
values.reverse();
alert(values); //5,4,3,2,1
let values = [0, 1, 5, 10, 15];
values.sort();
alert(values); //0,1,10,15,5
對于數值類型或者其valueOf()方法會返回數值類型的對象類型,可以使用一個更簡單的比較函數。這個函數只要用第二個值減第一個值即可。
let arr = [1,5,6,8,3,6,9];
function compare(value1, value2){
return value2 - value1;
};
alert(arr.sort(compare)); //[9, 8, 6, 6, 5, 3, 1]
想要實現從小到大排列就用value1-value2
2.6 操作方法
concat()方法可以基于當前數組中的所有項創建一個新數組。具體來說,這個方法會先創建當前數組一個副本,然后將接收到的參數添加到這個副本的末尾,最后返回新構建的數組。在沒有給concat()方法傳遞參數的情況下,它只是復制當前數組并返回副本。如果傳遞給concat()方法的是一或多個數組,則該方法會將這些數組中的每一項都添加到結果數組中。如果傳遞的值不是數組,這些值就會被簡單地添加到結果數組的末尾。注意:concat()方法不會影響原始數組
let colors = ["red", "green", "blue"];
let colors2 = colors.concat("blue", ["red", "brown"]);
alert(colors); //red,green,blue
alert(colors2); //red,green,blue,blue,red,brown
下一個方法是slice(),它能夠基于當前數組中的一或多個項創建一個新數組。slice()方法可以接受一或兩個參數,即要返回項的起始和結束位置。在只有一個參數的情況下,slice()方法返回從該參數指定位置開始到當前數組末尾的所有項。如果有兩個參數,該方法返回起始和結束位置之間的項——但不包括結束位置的項。注意,slice()方法不會影響原始數組。
let colors = ["red", "green", "blue", "yellow", "purple"];
let colors2 = colors.slice(1);
let colors3 = colors.slice(1,4);
alert(colors2); //green,blue,yellow,purple
alert(colors3); //green,blue,yellow
splice()方法,這個方法恐怕要算是最強大的數組方法了,它有很多種用法。
splice()的主要用途是向數組的中部插入項,但使用這種方法的方式則有如下3 種。
- 刪除:可以刪除任意數量的項,只需指定2 個參數:要刪除的第一項的位置和要刪除的項數。
例如,splice(0,2)會刪除數組中的前兩項。
- 插入:可以向指定位置插入任意數量的項,只需提供3 個參數:起始位置、0(要刪除的項數)和要插入的項。如果要插入多個項,可以再傳入第四、第五,以至任意多個項。
例如,splice(2,0,"red","green")會從當前數組的位置2 開始插入字符串"red"和"green"。
- 替換:可以向指定位置插入任意數量的項,且同時刪除任意數量的項,只需指定3 個參數:起始位置、要刪除的項數和要插入的任意數量的項。插入的項數不必與刪除的項數相等。
例如,splice (2,1,"red","green")會刪除當前數組位置2 的項,然后再從位置2 開始插入字符串"red"和"green"。
splice()方法始終都會返回一個數組,該數組中包含從原始數組中刪除的項(如果沒有刪除任何項,則返回一個空數組)而且修改的其實就是原數組,所以會影響原數組。
let colors = ["red", "green", "blue"];
let removed = colors.splice(0,1); // 刪除第一項
alert(colors); // green,blue
alert(removed); // red,返回的數組中只包含一項
removed = colors.splice(1, 0, "yellow", "orange"); // 從位置1 開始插入兩項
alert(colors); // green,yellow,orange,blue
alert(removed); // 返回的是一個空數組
removed = colors.splice(1, 1, "red", "purple"); // 插入兩項,刪除一項
alert(colors); // green,red,purple,orange,blue
alert(removed); // yellow,返回的數組中只包含一項
2.7 位置方法
indexOf()和lastIndexOf()。這兩個方法都接收兩個參數:要查找的項和(可選的)表示查找起點位置的索引。其中,indexOf()方法從數組的開頭(位置0)開始向后查找,lastIndexOf()方法則從數組的末尾開始向前查找。
這兩個方法都返回要查找的項在數組中的位置,或者在沒找到的情況下返回-1。在比較第一個參數與數組中的每一項時,會使用全等操作符;也就是說,要求查找的項必須嚴格相等(就像使用===一樣)。
let numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4)); //3
alert(numbers.lastIndexOf(4)); //5
alert(numbers.indexOf(4, 4)); //5
alert(numbers.lastIndexOf(4, 4)); //3
var person = { name: "Nicholas" };
var people = [{ name: "Nicholas" }];
var morePeople = [person];
alert(people.indexOf(person)); //-1
alert(morePeople.indexOf(person)); //0
使用indexOf()和lastIndexOf()方法查找特定項在數組中的位置非常簡單,支持它們的瀏覽器包括IE9+、Firefox 2+、Safari 3+、Opera 9.5+和Chrome。
2.8 迭代方法
數組定義了5 個迭代方法。每個方法都接收兩個參數:要在每一項上運行的函數和(可選的)運行該函數的作用域對象——影響this 的值。傳入這些方法中的函數會接收三個參數:數組項的值、該項在數組中的位置和數組對象本身。根據使用的方法不同,這個函數執行后的返回值可能會也可能不會影響方法的返回值。
- every():對數組中的每一項運行給定函數,如果該函數對每一項都返回true,則返回true。
- filter():對數組中的每一項運行給定函數,返回該函數會返回true 的項組成的數組。
- forEach():對數組中的每一項運行給定函數。這個方法沒有返回值。
- map():對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
- some():對數組中的每一項運行給定函數,如果該函數對任一項返回true,則返回true。
以上方法都不會修改數組中的包含的值。
在這些方法中,最相似的是every()和some(),它們都用于查詢數組中的項是否滿足某個條件。對every()來說,傳入的函數必須對每一項都返回true,這個方法才返回true;否則,它就返回false。而some()方法則是只要傳入的函數對數組中的某一項返回true,就會返回true。
- 最后一個方法是forEach(),它只是對數組中的每一項運行傳入的函數。這個方法沒有返回值,本質上與使用for 循環迭代數組一樣。
let numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
//執行某些操作
});
這些數組方法通過執行不同的操作,可以大大方便處理數組的任務。支持這些迭代方法的瀏覽器有IE9+、Firefox 2+、Safari 3+、Opera 9.5+和Chrome。
2.9 歸并方法
ECMAScript 5 還新增了兩個歸并數組的方法:reduce()和reduceRight()。這兩個方法都會迭代數組的所有項,然后構建一個最終返回的值。其中,reduce()方法從數組的第一項開始,逐個遍歷到最后。而reduceRight()則從數組的最后一項開始,向前遍歷到第一項。
這兩個方法都接收兩個參數:一個在每一項上調用的函數和(可選的)作為歸并基礎的初始值。傳給reduce()和reduceRight()的函數接收4 個參數:前一個值、當前值、項的索引和數組對象。這個函數返回的任何值都會作為第一個參數自動傳給下一項。第一次迭代發生在數組的第二項上,因此第一個參數是數組的第一項,第二個參數就是數組的第二項
。
使用reduce()方法可以執行求數組中所有值之和的操作,比如:
let values = [1,2,3,4,5];
let sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
第一次執行回調函數,prev 是1,cur 是2。第二次,prev 是3(1 加2 的結果),cur 是3(數組的第三項)。這個過程會持續到把數組中的每一項都訪問一遍,最后返回結果。reduceRight()的作用類似,只不過方向相反而已。
支持這兩個歸并函數的瀏覽器有IE9+、Firefox 3+、Safari 4+、Opera 10.5 和Chrome。