使用JS也算有段時日,然對於數組的使用,總侷限於很初級水平,且往往使用總要查下API,或者寫個小Demo測試下才算放心,一來二去,浪費很多時間;思慮下,堪能如此繼續之?當狠心深學下方是正道。html
var arrayObj = new Array(); //建立一個數組 var arrayObj = new Array([size]); //建立一個數組並指定長度,注意不是上限,是長度 var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]); //建立一個數組並賦值
要說明的是,雖然第二種方法建立數組指定了長度,但實際上全部狀況下數組都是變長的,也就是說即便指定了長度爲5,仍然能夠將元素存儲在規定長度之外的,注意:這時長度會隨之改變正則表達式
var testGetArrValue=arrayObj[1]; //獲取數組的元素值 arrayObj[1]= "這是新值"; //給數組元素賦予新的值
arrayObj. push([item1 [item2 [. . . [itemN ]]]]);// 將一個或多個新元素添加到數組結尾,並返回數組新長度 arrayObj.unshift([item1 [item2 [. . . [itemN ]]]]);// 將一個或多個新元素添加到數組開始,數組中的元素自動後移,返回數組新長度 arrayObj.splice(insertPos,0,[item1[, item2[, . . . [,itemN]]]]);//將一個或多個新元素插入到數組的指定位置,插入位置的元素自動後移,返回""。
arrayObj.pop(); //移除最後一個元素並返回該元素值 arrayObj.shift(); //移除最前一個元素並返回該元素值,數組中元素自動前移 arrayObj.splice(deletePos,deleteCount); //刪除從指定位置deletePos開始的指定數量deleteCount的元素,數組形式返回所移除的元素
arrayObj.slice(start, [end]); //以數組的形式返回數組的一部分,注意不包括 end 對應的元素,若是省略 end 將複製 start 以後的全部元素 arrayObj.concat([item1[, item2[, . . . [,itemN]]]]); //將多個數組(也能夠是字符串,或者是數組和字符串的混合)鏈接爲一個數組,返回鏈接好的新的數組
arrayObj.slice(0); //返回數組的拷貝數組,注意是一個新的數組,不是指向 arrayObj.concat(); //返回數組的拷貝數組,注意是一個新的數組,不是指向
arrayObj.reverse(); //反轉元素(最前的排到最後、最後的排到最前),返回數組地址 arrayObj.sort(); //對數組元素排序,返回數組地址
join()
方法是一個很是實用的方法,它把當前Array的每一個元素都用指定的字符串鏈接起來,而後返回鏈接後的字符串:編程
arrayObj.join(separator); //返回字符串,這個字符串將數組的每個元素值鏈接在一塊兒,中間用 separator 隔開。 var arr = ['A', 'B', 'C', 1, 2, 3]; arr.join('-'); // 'A-B-C-1-2-3'
若是Array的元素不是字符串,將自動轉換爲字符串後再鏈接。segmentfault
valueOf
: 與String相似,Array也能夠經過indexOf()來搜索一個指定的元素的位置:數組
var arr = [10, 20, '30', 'xyz']; arr.indexOf(10); // 元素10的索引爲0 arr.indexOf(30); // 元素30沒有找到,返回-1 arr.indexOf('30'); // 元素'30'的索引爲2
toLocaleString 、toString:能夠看做是join的特殊用法,不經常使用;
toLocaleString(): 方法可根據本地時間把 Date 對象轉換爲字符串,並返回結果。瀏覽器
toString:把數組轉換爲字符串,並返回結果。app
lastIndexOf:返回在數組中搜索到的與給定參數相等的元素的最後(最大)索引。框架
toSource(): 返回一個字符串,表明該數組的源代碼.<font color="red">該特性是非標準的,請儘可能不要在生產環境中使用它!</font> Array.prototype.toSource()編程語言
Length屬性表示數組的長度,即其中元素的個數。由於數組的索引老是由0開始,因此一個數組的上下限分別是:0和length-1。和其餘大多數語言不一樣的是,JavaScript數組的length屬性是可變的,這一點須要特別注意。當length屬性被設置得更大時,整個數組的狀態事實上不會發生變化,僅僅是length屬性變大;當length屬性被設置得比原來小時,則原先數組中索引大於或等於length的元素的值所有被丟失。下面是演示改變length屬性的例子:函數
var arr=[12,23,5,3,25,98,76,54,56,76];//定義了一個包含10個數字的數組 alert(arr.length); //顯示數組的長度10 arr.length=12; //增大數組的長度 alert(arr.length); //顯示數組的長度已經變爲12 alert(arr[8]); //顯示第9個元素的值,爲56 arr.length=5; //將數組的長度減小到5,索引等於或超過5的元素被丟棄 alert(arr[8]); //顯示第9個元素已經變爲"undefined" arr.length=10; //將數組長度恢復爲10 alert(arr[8]); //雖然長度被恢復爲10,但第9個元素卻沒法收回,顯示"undefined"
由上面的代碼咱們能夠清楚的看到length屬性的性質。但length對象不只能夠顯式的設置,它也有可能被隱式修改。JavaScript中可使用一個未聲明過的變量,一樣,也可使用一個未定義的數組元素(指索引超過或等於length的元素),這時,length屬性的值將被設置爲所使用元素索引的值加1。例以下面的代碼:
var arr=[12,23,5,3,25,98,76,54,56,76]; console.log(arr.length); // 10 arr[15] = 34; console.log(arr.length); //16 console.log(arr[10]); //undefine console.log(arr.toString()) //12,23,5,3,25,98,76,54,56,76,,,,,,34
代碼中一樣是先定義了一個包含10個數字的數組,經過alert語句能夠看出其長度爲10。隨後使用了索引爲15的元素,將其賦值爲15,即 arr[15]=34,這時再用alert語句輸出數組的長度,獲得的是16。不管如何,對於習慣於強類型編程的開發人員來講,這是一個很使人驚訝的特性。事實上,使用new Array()形式建立的數組,其初始長度就是爲0,正是對其中未定義元素的操做,才使數組的長度發生變化。
大多數其餘編程語言不容許直接改變數組的大小,越界訪問索引會報錯。然而,JavaScript的Array卻不會有任何錯誤。在編寫代碼時,不建議直接修改Array的大小,訪問索引時要確保索引不會越界。
由上面的介紹能夠看到,length屬性是如此的神奇,利用它能夠方便的增長或者減小數組的容量。所以對length屬性的深刻了解,有助於在開發過程當中靈活運用。
返回對象類型原型的引用。prototype 屬性是 object 共有的。
objectName.prototype:objectName 參數是object對象的名稱。
說明:用 prototype 屬性提供對象的類的一組基本功能。 對象的新實例「繼承」賦予該對象原型的操做。
對於數組對象,以如下例子說明prototype 屬性的用途。
給數組對象添加返回數組中最大元素值的方法。要完成這一點,聲明一個函數,將它加入 Array.prototype, 並使用它。
function array_max() { var i, max = this[0]; for (i = 1; i < this.length; i++) { if (max < this[i]) max = this[i]; } return max; } Array.prototype.max = array_max; var x = new Array(1, 2, 3, 4, 5, 6); var y = x.max();
該代碼執行後,y 保存數組 x 中的最大值,即:6。
表示建立對象的函數。object.constructor //object是對象或函數的名稱。
說明:constructor 屬性是全部具備 prototype 的對象的成員。它們包括除 Global 和 Math 對象之外的全部 JScript 固有對象。constructor 屬性保存了對構造特定對象實例的函數的引用。
x = new String("Hi"); if (x.constructor == String) // 進行處理(條件爲真)。 function MyFunc { // 函數體。 } y = new MyFunc; if (y.constructor == MyFunc) // 進行處理(條件爲真)。 y = new Array();
js由於設計上的某些缺陷,致使在對於Array的判斷,也是頗費周折的。
typeof 操做符
:對於Function, String, Number ,Undefined 等幾種類型的對象來講,他徹底能夠勝任,可是爲Array時,不免會讓人失望:
var arr=new Array("1","2","3","4","5"); alert(typeof(arr)); // Object
instanceof 操做符
: 運算符會返回一個 Boolean 值,指出對象是不是特定類的一個實例。
var arrayStr=new Array("1","2","3","4","5"); alert(arrayStr instanceof Array); //true
雖然此時可以無缺的工做,但,事實上在多個frame中穿梭就會產生大問題了。因此~~~
var iframe = document.createElement('iframe'); document.body.appendChild(iframe); xArray = window.frames[window.frames.length-1].Array; var arr = new xArray("1","2","3","4","5");//這個寫法IE大哥下是不支持的,FF下才有 alert(arr instanceof Array); // false alert(arr.constructor === Array); // false
ECMA-262中規範定義了Object.prototype.toString的行爲:首先,取得對象的一個內部屬性[[Class]],而後依據這個屬性,返回一個相似於"[object Array]"的字符串做爲結果(看過ECMA標準的應該都知道,[[]]用來表示語言內部用到的、外部不可直接訪問的屬性,稱爲「內部屬性」)。利用這個方法,再配合call,咱們能夠取得任何對象的內部屬性[[Class]],而後把類型檢測轉化爲字符串比較,以達到咱們的目的。因而利用這點,就有了下面這種方法:
function isArray(obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }
call改變toString的this引用爲待檢測的對象,返回此對象的字符串表示,而後對比此字符串是不是'[object Array]',以判斷其是不是Array的實例。也許你要問了,爲何不直接o.toString()?嗯,雖然Array繼承自Object,也會有toString方法,可是這個方法有可能會被改寫而達不到咱們的要求,而Object.prototype則是老虎的屁股,不多有人敢去碰它的,因此能必定程度保證其「純潔性」:)。這也是Array.isArray()方法的兼容舊環境(Polyfill)。
如此很好的解決了跨frame對象構建的問題,通過測試,各大瀏覽器兼容性也很好,能夠放心使用。不少框架,好比jQuery、Base2等等,都計劃借鑑此方法以實現某些特殊的,好比數組、正則表達式等對象的類型斷定!固然也能夠寫成以下這樣:
function isArray2 (v){ return toString.apply(v) === '[object Array]'; }
要注意的是:toString方法極有可能被重寫,因此須要使用的時候,能夠直接使用Object.prototype.toString()方法。
Array.isArray()
See方法用來判斷某個值是否爲數組。若是是,則返回 true,不然返回 false。
// 下面的函數調用都返回 true Array.isArray([]); Array.isArray([1]); Array.isArray(new Array()); // 不爲人知的事實:其實 Array.prototype 也是一個數組。 Array.isArray(Array.prototype); // 下面的函數調用都返回 false Array.isArray(); Array.isArray({}); Array.isArray(null); Array.isArray(undefined); Array.isArray(17); Array.isArray('Array'); Array.isArray(true); Array.isArray(false); Array.isArray({ __proto__: Array.prototype });
方法使用指定的函數測試全部元素,並建立一個包含全部經過測試的元素的新數組。
語法:arr.filter(callback[, thisArg])
若是爲 filter 提供一個 thisArg 參數,則它會被做爲 callback 被調用時的 this 值。不然,callback 的 this 值在非嚴格模式下將是全局對象,嚴格模式下爲 undefined。
filter 爲數組中的每一個元素調用一次 callback 函數,並利用全部使得 callback 返回 true 或 等價於 true 的值 的元素建立一個新數組。callback 只會在已經賦值的索引上被調用,對於那些已經被刪除或者從未被賦值的索引不會被調用。那些沒有經過 callback 測試的元素會被跳過,不會被包含在新數組中。
示例:篩選排除掉全部的小值
function isBigEnough(element) { return element >= 10; } var filtered = [12, 5, 8, 130, 44].filter(isBigEnough); // filtered is [12, 130, 44]
方法讓數組的每一項都執行一次給定的函數。
語法: array.forEach(callback[, thisArg])
forEach 方法按升序爲數組中含有效值的每一項執行一次callback 函數,那些已刪除(使用delete方法等狀況)或者從未賦值的項將被跳過(但不包括哪些值爲 undefined 的項)。
forEach 遍歷的範圍在第一次調用 callback 前就會肯定。調用forEach 後添加到數組中的項不會被 callback 訪問到。若是已經存在的值被改變,則傳遞給 callback 的值是 forEach 遍歷到他們那一刻的值。已刪除的項不會被遍歷到。 注意: 沒有辦法停止 forEach 循環。若是要停止,可以使用 Array.every 或 Array.some。見下面的例子。
示例1:打印出數組的內容
function logArrayElements(element, index, array) { console.log("a[" + index + "] = " + element); } [2, 5, 9].forEach(logArrayElements); // logs: // a[0] = 2 // a[1] = 5 // a[2] = 9
示例2:一個能夠克隆對象的函數
使用下面的代碼能夠複製一個給定的對象,雖然有不少不一樣的複製對象的方法.不過下面介紹的這種方法使用了Array.prototype.forEach和其餘一些ECMAScript 5中的Object.*函數.
function copy(o){ var copy = Object.create( Object.getPrototypeOf(o) ); var propNames = Object.getOwnPropertyNames(o); propNames.forEach(function(name){ var desc = Object.getOwnPropertyDescriptor(o, name); Object.defineProperty(copy, name, desc); }); return copy; } var o1 = {a:1, b:2}; var o2 = copy(o1); // o2 looks like o1 now
方法測試數組的全部元素是否都經過了指定函數的測試。
語法:arr.every(callback[, thisArg])
every 方法爲數組中的每一個元素執行一次 callback 函數,直到它找到一個使 callback 返回 falsy(表示可轉換爲布爾值 false 的值)的元素。若是發現了一個這樣的元素,every 方法將會當即返回 false。不然,callback 爲每個元素返回 true,every 就會返回 true。callback 只會爲那些已經被賦值的索引調用。不會爲那些被刪除或歷來沒被賦值的索引調用。callback 被調用時傳入三個參數:元素值,元素的索引,原數組。 every 不會改變原數組。
實例:檢測全部數組元素的大小
//檢測數組中的全部元素是否都大於 10 function isBigEnough(element, index, array) { return (element >= 10); } var passed = [12, 5, 8, 130, 44].every(isBigEnough); // passed is false passed = [12, 54, 18, 130, 44].every(isBigEnough); // passed is true
方法返回一個由原數組中的每一個元素調用一個指定方法後的返回值組成的新數組。
語法: array.map(callback[, thisArg])
map 方法會給原數組中的每一個元素都按順序調用一次 callback 函數。callback 每次執行後的返回值組合起來造成一個新數組。 callback 函數只會在有值的索引上被調用;那些歷來沒被賦過值或者使用 delete 刪除的索引則不會被調用。map 不修改調用它的原數組自己(固然能夠在 callback 執行時改變原數組)。
實例一:求數組中每一個元素的平方根
//在一個 String 上使用 map 方法獲取字符串中每一個字符所對應的 ASCII 碼組成的數組: var map = Array.prototype.map var a = map.call("Hello World", function(x) { return x.charCodeAt(0); }) // a的值爲[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
一般狀況下,map 方法中的 callback 函數只須要接受一個參數,就是正在被遍歷的數組元素自己。但這並不意味着 map 只給 callback 傳了一個參數。這個思惟慣性可能會讓咱們犯一個很容易犯的錯誤。好比下面的語句返回什麼呢:
["1", "2", "3"].map(parseInt); // 你可能覺的會是[1, 2, 3] // 但實際的結果是 [1, NaN, NaN]
一般使用parseInt時,只須要傳遞一個參數.但實際上,parseInt能夠有兩個參數.第二個參數是進制數.能夠經過語句"alert(parseInt.length)===2"來驗證.
map方法在調用callback函數時,會給它傳遞三個參數:當前正在遍歷的元素, 元素索引, 原數組自己.
第三個參數parseInt會忽視, 但第二個參數不會,也就是說,parseInt把傳過來的索引值當成進制數來使用.從而返回了NaN。 所以此時應該使用以下的用戶函數returnInt:
function returnInt(element){ return parseInt(element,10); } ["1", "2", "3"].map(returnInt); // 返回[1,2,3]
方法測試數組中的某些元素是否經過了指定函數的測試。
語法: arr.some(callback[, thisArg])
描述:some 爲數組中的每個元素執行一次 callback 函數,直到找到一個使得 callback 返回一個「真值」(便可轉換爲布爾值 true 的值)。若是找到了這樣一個值,some 將會當即返回 true。不然,some 返回 false。callback 只會在那些」有值「的索引上被調用,不會在那些被刪除或歷來未被賦值的索引上調用。
示例:測試數組元素的值
//檢測在數組中是否有元素大於 10。 function isBigEnough(element, index, array) { return (element >= 10); } var passed = [2, 5, 8, 1, 4].some(isBigEnough); // passed is false passed = [12, 5, 8, 1, 4].some(isBigEnough); // passed is true
接收一個函數做爲累加器(accumulator),數組中的每一個值(從左到右)開始縮減,最終爲一個值。
語法: arr.reduce(callback,[initialValue])
callback:執行數組中每一個值的函數,包含四個參數
描述:reduce 爲數組中的每個元素依次執行回調函數,不包括數組中被刪除或從未被賦值的元素,接受四個參數:初始值(或者上一次回調函數的返回值),當前元素值,當前索引,調用 reduce 的數組。
回調函數第一次執行時,previousValue 和 currentValue 能夠是一個值,若是 initialValue 在調用 reduce 時被提供,那麼第一個 previousValue 等於 initialValue ,而且currentValue 等於數組中的第一個值;若是initialValue 未被提供,那麼previousValue 等於數組中的第一個值,currentValue等於數組中的第二個值。
若是數組爲空而且沒有提供initialValue, 會拋出TypeError 。若是數組僅有一個元素(不管位置如何)而且沒有提供initialValue, 或者有提供initialValue可是數組爲空,那麼此惟一值將被返回而且callback不會被執行。
示例1:將數組全部項相加
var total = [0, 1, 2, 3].reduce(function(a, b) { return a + b; }); // total == 6
示例2: 數組扁平化
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) { return a.concat(b); }); // flattened is [0, 1, 2, 3, 4, 5]
示例2: 統計一個數組中有多少個不重複的單詞
不使用reduce時的寫法
var arr = ["apple","orange","apple","orange","pear","orange"]; function getWordCnt(){ var obj = {}; for(var i= 0, l = arr.length; i< l; i++){ var item = arr[i]; obj[item] = (obj[item] +1 ) || 1; } return obj; } console.log(getWordCnt());
使用reduce()後的寫法:
var arr = ["apple","orange","apple","orange","pear","orange"]; function getWordCnt(){ return arr.reduce(function(prev,next){ prev[next] = (prev[next] + 1) || 1; return prev; },{}); } console.log(getWordCnt());
這其中一個須要注意的點在於,initialValue提供與否對prev和next的影響;
/* 兩者的區別,在console中運行一下便可知曉*/ var arr = ["apple","orange",'pear','jade']; function noPassValue(){ return arr.reduce(function(prev,next){ console.log("prev:",prev); console.log("next:",next); //console.info('prev type:'+ typeof(prev)); //prev type:string return prev + " " +next; }); } function passValue(){ return arr.reduce(function(prev,next){ console.log("prev:",prev); console.log("next:",next); prev[next] = 1; //console.info('prev type:'+ typeof(prev)); // object return prev; },{}); } console.log("No Additional parameter:",noPassValue()); console.log("----------------"); console.log("With {} as an additional parameter:",passValue());
pop,push,reverse,shift,sort,splice,unshift 會改變原數組
join,concat,indexOf,lastIndexOf,slice,toString 不會改變原數組
map,filter,some,every,reduce,forEach這些迭代方法不會改變原數組
幾個注意點:
JavaScript的數據類型分爲:值類型和引用類型(地址值);而常見的引用類型有Object和Array/數組的存儲模型中,若是是諸如Number,String之類的類型數據會被直接壓入棧中,而引用類型只會壓入對該值的一個索引(即C中所說的保存了數據的指針)。這些數據時儲存在堆中的某塊區間中,堆棧並非獨立的,棧中也能夠在堆中存放。在使用Array的進行賦值操做的時候,也當注意是否要進行深度拷貝複製(可藉助arr.slice(0)),以避免形成對自身污染。對於Js數據,其實內容仍是還有不少須要學習的,好比ArrayBuffer等。根據學以至用的原則,這些等到須要的時候再去學吧。
原文連接http://www.jeffjade.com/2015/09/25/2015-09-25-js-array
參考文章以下:
js數組操做
js如何判斷一個對象是否是Array?
MDN-Array
盤點JavaScript裏好用的原生API
5個如今就該使用的數組Array方法