JavaScript數組是一種特殊類型的對象。
JavaScript數組元素能夠爲任意類型,最大容納232-1個元素。
JavaScript數組是動態的,有新元素添加時,自動更新length屬性。
JavaScript數組元素索引能夠是不連續的,它們之間能夠有空缺。javascript
調用構造函數Array()建立數組:java
var a = new Array(); //空數組,等同於數組直接量[] var b = new Array(5); //建立指定長度的數組 var c = new Array(1, 5, 9, 6); //指定一個或多個元素的非空數組
數組直接量表示法:數組
var a = []; //空數組 var b = [2, 3, 5, 7]; //常規元素 var c = [5, true, "a"]; //元素不一樣類型的數組 var d = [{ x: 2 }, { x: 3 }]; //包含對象元素的數組
以上是數組的幾種常見類型,但下面兩種也符合數組語法。瀏覽器
var e = [1, , 3]; //該數組有3個元素,中間的元素爲undefined var f = [1, 5, ]; //該數組有2個元素,結尾逗號後面沒有元素
若是省略數組直接量中的某個元素值,省略的元素值爲undefined
;
數組直接量的語法中容許有可選結尾的逗號,故[1,5,]
只有兩個元素並不是三個。app
兩種方法建立的數組無本質區別,但數組直接量表示法簡單,實際使用中更爲常見。函數
讀寫數組元素最簡單的方法就是經過索引。測試
var arr = ["one", "two"]; var res = arr[0]; //讀第0的元素 arr[0] = "test"; //寫第0的元素
數組自己就是對象,使用[]
方括號訪問數組元素就像方括號訪問對象屬性同樣。數組的特別之處在於,當使用小於232的非負整數做爲屬性時數組會自動維護其length
屬性。固然,數組也能夠有自定義屬性,但不常見。以下:ui
var obj = [1, 2, 3]; obj["IsShow"] = false; //如今obj數組爲 [1, 2, 3, IsShow: false]
稀疏數組就是包含從0開始的不連續索引的數組。this
var a = new Array(5); //數組沒有元素,但a.length等於5 var b = []; b[1000] = 1000; //添加一個索引爲1000的元素,但b.length等於1001
經過delete
操做符刪除數組元素可產生稀疏數組。delete
不會改變數組長度,高位置索引元素也不會下移填補刪除索引位置的空白。prototype
注意,省略數組不等同於稀疏數組,省略的元素在數組中是存在的,值爲undefined
。
每一個數組都有length
屬性,表明數組中元素的個數。針對非稀疏數組,其值比最大索引大1。
['a', 'b', 'c'].length; //最大索引爲2,length爲3
當設置length
屬性爲一個小於當前數組長度的非負整數n時,當前數組中的那些索引大於或等於n的元素將被刪除。
var a = [1, 2, 3, 4, 5]; //數組初始化5個元素 a.length = 3; //如今a爲[1,2,3] a.length = 0; //刪除全部元素,a爲[] a.length = 5; //數組長度爲5,可是沒有元素
在ECMAScript 5中,能夠用Object.defineProperty()
讓數組的length
屬性變成只讀的。
var b = [1, 2, 3]; Object.defineProperty(b, "length", { writable: false }); //讓length變成只讀屬性 b.length = 0; //更改無效
使用for循環遍歷數組元素是最多見的方法。以下:
var obj = { height: 175, weight: 60 }; //初始化一個對象 var keys = Object.keys(obj); //獲取對象obj屬性名組成的數組 var values = []; //values用來保存對象obj屬性值 for (var i = 0, len = keys.length; i < len; i++) { var key = keys[i]; //獲取當前索引的鍵值 values[i] = obj[key]; //在values數組中保存屬性值 }
針對稀疏數組遍歷時,注意過濾掉不知足條件的元素。
for (var i = 0; i < arr.length; i++) { if (!arr[i]) continue; //跳過null,undefined和不存在的元素 if (arr[i] === undefined) continue; //跳過undefined和不存在的元素 if (!(i in arr)) continue; //跳過不存在的元素 //T0DO }
JavaScript不支持真正的多維數組,通常用數組的數組來近似。下面是一個具體的例子,使用二維數組做爲一個9X9乘法表。
//建立一個多維數組 var table = new Array(10); //表格有10行 for (var i = 0; i < table.length; i++) { table[i] = new Array(10); //每行有10列 } //初始化數組 for (var row = 0; row < table.length; row++) { for (var col = 0; col < table[row].length; col++) { table[row][col] = row * col; } } //使用多維數組來計算 var result = table[8][9]; //result = 72
ECMAScript 3在Array.prototype中定義了一些頗有用的操做數組的方法,下面介紹這些方法的基本用法。
join()
Array.join(separator)
該方法能夠將數組元素按照指定字符鏈接起來,返回最終生成的字符串。若是不指定字符separator
,默認用逗號分隔。
var arr = [1, 2, 3]; arr.join(); //=>"1,2,3" 默認使用逗號做爲元素鏈接符 arr.join(' '); //=>"1 2 3" 以空格做爲鏈接符 arr.join('|'); //=>"1|2|3" 以‘|’做爲鏈接符
reverse()
Array.reverse()
該方法將數組中的的元素顛倒順序,在原數組上進行操做。方法返回值爲對原來數組的引用。
var arr = [1, 2, 3]; arr.reverse().join(); //=>"3,2,1" ,而且如今arr爲[3,2,1]
sort()
Array.sort([compareFunction])
該方法將數組中的元素排序並返回對原來數組的引用。不傳遞參數調用時,默認按照字母順序排序。
var fruits = ['banana', 'cherry', 'apple']; fruits.sort().join(); //=>apple,banana,cherry
當按照其餘方式排序時,就要提供一個比較函數compareFunction
。該函數要比較兩個值,而後返回一個用於說明這兩個值的相對順序的數字。比較函數應該具備兩個參數 a 和 b,其返回值以下:
var s = [33, 666, 12, 5]; s.sort(); //字母順序:12,33,5,666 s.sort(function (a, b) { //數字順序:5,12,33,666 return a - b; });
若是要排序的數組元素包含undefined
,它們會被排到數組尾部。
concat()
Array.concat(arr1[,arr2,...])
該方法用於鏈接兩個或多個數組並返回一個新數組,不會改變現有數組自己。
var a = [1, 2]; a.concat(4, 5); //=>[1,2,4,5] 鏈接每個參數值 a.concat([4, 5]); //=>[1,2,4,5] 鏈接一個數組 a.concat([4, 5], [6, 7]); //=>[1,2,4,5,6,7] 鏈接多個數組
slice()
Array.slice(start[,end])
該方法用來從已有的數組返回選定的元素,返回一個新的數組。兩個參數分別指定要選定元素的開始位置和結束位置。
start
參數表示從什麼位置開始取。若是是負數,那麼它規定從數組尾部開始算起的位置。也就是說,-1 指最後一個元素,-2 指倒數第二個元素,以此類推。end
是一個可選參數。規定從何處結束選取,但不包括該下標元素。若是沒有指定該參數,那麼切分的數組包含從 start 到數組結束的全部元素。若是這個參數是負數,那麼它規定的是從數組尾部開始算起的元素。var a = [1, 2, 3, 4, 5]; a.slice(0, 3); //返回[1,2,3] a.slice(3); //返回[4,5] a.slice(1, -1); //返回[2,3,4] a.slice(-3, -2); //返回[3]
splice()
Array.splice(index,count[, item1[, item2[, ...]]])
該方法用來向數組中添加或刪除元素,而且用參數列表中聲明的一個或多個值來替換那些被刪除的元素。返回被刪除的元素。該方法會改變原始數組。
index
參數表明要添加或刪除元素的索引。count
參數表明要從數組中刪除的元素個數。若是省略,從index
起點到數組結尾的元素全刪除。item1,item2,...
從第三個參數開始是可選參數。表明向數組添加的新元素。var names = ["George", "Thomas"]; names.splice(1, 0, "John"); //在索引爲1的地方插入一個新元素 names.splice(0, 1, "Tom"); //將第一個元素'George'替換成'Tom'
splice()
與slice()
方法,一個字母之差可是功能徹底不一樣,注意區別使用。
push()和pop()
Array.push(element1,element2,...)
該方法用來向數組的末尾添加一個或多個元素,並返回新的長度。
Array.pop()
方法用來刪除數組的最後一個元素,減少數組長度,返回刪除的元素值。
組合push()
和pop()
可以讓JavaScript數組實現先進後出的棧功能:push()
入棧、pop()
出棧。
var stack = []; //空棧 stack.push(1, 2); //stack:[1,2] stack.pop(); //stack:[1] stack.push(3); //stack:[1,3] stack.pop(); //stack:[1] stack.push([4, 5]); //stack:[1,[4, 5]] stack.pop(); //stack:[1] stack.pop(); //stack:[]
unshift()和shift()
Array.unshift(element1,element2,...)
該方法可向數組的開頭添加一個或更多元素,並返回新的長度。
Array.shift()
方法用於把數組的第一個元素從其中刪除,並返回第一個元素的值。若是數組爲空,shift()
不進行任何操做,返回undefined
。
這兩個方法行爲很是相似於push()
和pop()
。不同的是,這兩個方法是在數組頭部操做。
var arr = [3, 4]; arr.unshift(1,2); // arr:[1,2,3,4] arr.shift(); // arr:[2,3,4]
toString()和toLocalString()
數組對象和普通對象同樣擁有toString()
方法。該方法會將數組元素轉化爲字符串,用逗號把生成的字符串鏈接起來,造成一個字符串。返回值與沒有參數的join()
方法返回的字符串相同。
[1, 2, 3].toString(); //"1,2,3" ["a", "b", "c"].toString(); //"a,b,c" [1, [2, 'c']].toString(); //"1,2,c"
toLocalString()
是toString()
的本地化方法。
ECMAScript 5中定義了9個新的數組方法來遍歷,映射,過濾,檢測,簡化和搜索數組。有了這些方法就不用利用for循環來遍歷數組了。
forEach()
Array.forEach(callback[, thisArg])
方法用來從頭致尾遍歷數組,爲每一個元素調用回調方法。對於稀疏數組,不存在的元素不調用回調方法。
callback
參數就是在數組每一項上執行的函數,接收三個參數:數組元素、元素索引和數組自己。thisArg
是可選參數,用來看成callback
函數內this
的值的對象。若是省略了thisArg
參數,或者賦值爲null
或 undefined
,則 this
在非嚴格模式下將是全局對象,嚴格模式下爲 undefined
。下面看個綜合例子:以數組元素爲半徑,計算全部圓的面積。
var numbers = [5, 6]; // Define an array. var obj = { showResults: function(value, index,array) { var squared = this.calcSquare(value); document.write("value: " + value); document.write(" index: " + index); document.write(" squared: " + squared); document.write("<br />"); }, calcSquare: function(x) { return x * x } }; numbers.forEach(function(value, index) { this.showResults(value, index) }, obj); // Output: // value: 5 index: 0 squared: 25 // value: 6 index: 1 squared: 36
注意:沒有辦法停止或者跳出forEach
循環,除了拋出一個異常。它老是返回undefined
,即沒有返回值。
map()
Array.map(callback[, thisArg])
方法和forEach()
一樣是用來遍歷數組,爲每一個元素執行回調方法。該方法參數與forEach()
方法參數一致,再也不贅述。可是傳給map()
的函數應該有返回值。
var numbers = [1, 4, 9]; var roots = numbers.map(Math.sqrt); //求數組中每一個元素的平方根 /* roots的值爲[1, 2, 3], numbers的值仍爲[1, 4, 9] */
filter()
Array.filter(callback[, thisArg])
方法用來過濾數組元素,將符合規則的元素組成一個新數組返回,不會改變原數組。callback
參數就是用來測試數組中元素的方法,返回true
表示經過測試。
var arr = [1, 2, 3, 4, 5]; var res = arr.filter(function (value, index, array) { return value > 3; //過濾掉小於等於3的元素 }); alert(res.toString()); //=> 4,5
對其非稠密數組,壓縮刪除undefined
和null
元素,能夠這樣使用filter()
:
arr.filter(function (value) { return value != undefined && value != null; });
every()和some()
Array.every(callback[, thisArg])
該方法用來測試數組元素是否都經過了指定函數的測試。
Array.some(callback[, thisArg])
該方法用來測試數組某些元素是否經過了指定函數的測試。
這兩個方法就是數組的邏輯判斷。它們對數組元素調用指定方法,返回true
或false
。
var arr = [1, 2, 3, 4, 5]; arr.every(function (value) { return value < 10; }); //=>true 全部元素值<10 arr.every(function (value) { return value % 2 == 0; }); //false 並不是全部元素都爲偶數 arr.some(function (value) { return value % 2 == 0; }); //=>true 數組元素包含偶數 arr.some(isNaN); //=>false 數組不包含非數值元素
注意:當every()
和some()
已確認該返回什麼值的時候就會中止遍歷數組。
reduce()和reduceRight()
Array.reduce(callback[, initialValue])
該方法會針對數組中每一個元素調用指定回調函數,將回調函數的返回值做爲累積,而後以參數的形式傳遞到下個元素的回調方法中。
callback
參數是數組元素要執行的回調函數。最多可接收4個參數:以前元素累積值、當前元素值、元素索引、數組自己。initialValue
是可選參數,表示元素最開始調用回調函數傳入的初始值。若是缺省該參數,它會使用數組第一個元素做爲初始值,這樣數組就會少迭代一次。var arr = [1, 2, 3, 4]; var sum = arr.reduce(function (previous, current, index, array) { return previous + current; }, 5); var max = arr.reduce(function (previous, current, index, array) { return previous > current ? previous : current; }); console.log(sum); //=>15 求和 console.log(max); //=>4 求最大值
利用reduce()
能夠輕鬆實現二維數組的扁平化:
var matrix = [ [1, 2], [3, 4], [5, 6] ]; var flatten = matrix.reduce(function (previous, current) { return previous.concat(current); }); console.log(flatten); //=> [1, 2, 3, 4, 5, 6]
Array.reduceRight(callback[, initialvalue])
方法的用法與reduce()
方法一致,惟一區別是該方法按元素索引降序處理元素。
indexOf()和lastIndexOf()
Array.indexOf(searchvalue[, fromIndex])
方法用來搜索數組中給定值的元素,並返回該元素的索引,若是找不到指定的元素則返回-1。indexOf()
從數組頭至尾開始搜,Array.lastIndexOf(searchvalue[, fromIndex])
則相反,從數組尾部爲起點開始搜。
searchvalue
參數表明要搜索的元素值。fromindex
是可選參數,表示檢索的起始位置。其值能夠爲字符串數值;填入字符自動忽略,默認爲0。var data = [2, 5, 7, 3, 5]; console.log(data.indexOf(5, "x")); //=> 1 "x"被忽略,用0代替 console.log(data.indexOf(5, "3")); //=> 4 從3號位開始搜索
大多數瀏覽器都支持以上方法。針對低版本IE6-IE8瀏覽器兼容性問題,可經過Array原型擴展實現以上方法。例如forEach方法:
if (!Array.prototype.forEach) { Array.prototype.forEach = function (callback, thisArg) { //TODO }; }
數組是具備特殊行爲的對象。開發中可能會遇到這樣的狀況:給定一個未知對象,判斷它是否爲數組對象。ECMAScript 5版本中能夠用Array.isArray()
方法鑑別。
console.log(Array.isArray([])); //=> true console.log(Array.isArray({})); //=> false
在ECMAScript 5版本之前沒有Array.isArray()
這個方法,typeof
可解決大部分的數據類型判斷可是在這卻幫不上忙。
instanceof
操做符能夠檢測,但有侷限性,只能做用於單頁面的情形。
console.log([] instanceof Array); //=> true console.log({} instanceof Array); //=> false
當頁面中存在子頁面iframe時,在子頁面中聲明一個數組object
,並將其賦值給父頁面的一個變量,這時判斷該變量:object instanceof Array
會返回false
。緣由是數組是引用類型,在賦值過程當中,傳遞的是引用地址。可是每一個頁面都有本身的一套全局對象,而且每一個全局對象有本身的構造函數。object
是子頁面Array對象,傳遞到父頁面,在父頁面判斷時倒是以父頁面的Array對象爲標準。
ECMAScript 3版本中,檢測對象是否爲數組的isArray()
能夠這樣寫:
var isArray = Array.isArray() || function isArray(arg) { return typeof arg === 'object' && //是否爲對象 object.length === 'number' && //驗證length屬性 Object.prototype.toString.call(arg) === '[object Array]'; //判斷基本類型* }
根據數組的一些特性來判斷,上面一段代碼也正是ES5中Array.isArray()
方法的實現形式。
一般把一個具備與數組相仿屬性的常規對象叫作「類數組」對象,即具備length屬性
和對應非負正整數屬性
。類數組對象不能直接調用數組的方法,但能夠數組的形式遍歷。
//定義一個類數組對象 var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; //看成數組遍歷 for (var i = 0; i < obj.length; i++) { console.log(obj[i]); }
JavaScript函數體中Arguments
對象是一個類數組對象。一些DOM方法也返回類數組對象,好比
document.getElementsByTagName()
。
能夠用下面的方法檢查對象是否爲類數組:
function isArrayLike(o) { if (o && //判斷o非null,undefined等 typeof o === 'object' && //o是對象 isFinite(o.length) && //o.length是有限數 o.length > 0 && //o.length是非負數 o.length < 4294967296 && //o.length小於2^32 o.length === Math.floor(o.length)) //o.length是整數 return true; else return false; }
ES5版本中,全部Array數組方法都是通用的,類數組對象上一樣適用。類數組對象沒有繼承至Array.prototype
不能直接調用,但能夠經過Function.call
方法調用:
var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }; console.log(Array.prototype.join.call(obj, '|')); //=> a|b|c var arr = Array.prototype.map.call(obj, function (value) { return value.toUpperCase(); }); console.log(arr.join); //=> A,B,C 此時arr已經是真正的數組
本篇內容源自我對《JavaScript權威指南》第7章 數組 章節的閱讀總結和代碼實踐。總結的比較粗糙,你也可經過原著或MDN更深刻了解數組。
[1] David Flanagan,JavaScript權威指南(第6版)
[2] MDN,JavaScript 參考文檔 - Array - JavaScript | MDN