結合《javascript高級程序設計》《javascript權威指南》《javascript語言精粹》作的一篇關於Array對象的全面解析。分爲兩篇:基礎篇和擴展應用篇。javascript
數組是值的有序集合,每一個值稱爲一個元素,每一個元素在數組中有特定位置,以數字表示,稱爲索引,JavaScript中的數組是一個類數組的對象,雖然在性能上比真正的數組會慢,但它使用起來更方便。
前端
特色 | 說明 |
---|---|
元素類型任意性 | 數組元素能夠是基礎數據類型,對象,也能夠是數組 |
動態性 | 根據須要它們會增加或縮減,而且在變化時無需從新分配內存空間 |
稀疏性 | 數組元素的索引不必定是連續的,它們之間能夠有空缺, |
2.1 數組字面量方式 : 元素用逗號隔開便可。java
var empty = [];//建立空數組 var num = [1,2,3,4,5];//建立5個數值類型元素的的數組 var mix = [1,'jozo',true,[1,2],{1:'jozo'}];//建立任意類型元素的數組
2.2 構造函數方式 : 調用構造函數Array(),根據參數不一樣,建立不一樣的數組
a.不傳遞參數數組
var a = new Arry();//建立一個空數組,但咱們更經常使用下面的方式 var a = [];
b.傳遞一個數值參數,這個參數用來指定數組長度數據結構
var a = new Arry(5);// 建立了一個長度爲5的數組
c.傳遞多個參數,用這些參數做爲數組元素初始化數組。函數
var a = new Arry(1,'jozo',true,[1,2]);//構造函數的參數將會成爲數組元素
3.1 添加性能
a.經過索引添加學習
var a = []; a[0] = 'jozo';//此時 a = ['jozo'] a[1] = 'blog';//此時 a = ['jozo','blog']
b.經過數組方法添加this
push(),concat(),splice(),unshift()
方法均可覺得數組添加元素,後面將會詳細介紹。spa
3.2 刪除
a.刪除數組元素
var a = [1,2]; delet a[0];//刪除第一個元素 console.log(a[0]);//undefined console.log(a[1]);//2 console.log(a.length);//2
能夠看出,經過delete
運算符刪除數組元素也有一些注意的地方。1.
原數組長度不變。2.
被刪除的元素的值變爲undefined
.3.
數組內的其餘元素的索引沒有改變。其實就是原數組變成了稀疏數組
。
splice(),pop(),shift()
數組方法也能夠用於刪除數組元素,後面講解。
b.刪除整個數組對象
第一種方式:直接操做數組對象(推薦用法) var a = [1,2]; a.length = 0; console.log(a);//輸出: [] 第二種方式:改變變量的引用 (不算真正的刪除) var a = [1,2]; a = []; console.log(a);//輸出: []
其實上面的知識點不講咱們都差很少都知道的。可是數組的一些方法屬性咱們雖然知道可是卻不會用,或是老是忘記該怎麼用,由於它的方法屬性也不少,咱們來分析下各個方法的特色:
經常使用方法 | 說明 | 返回值 | 影響原數組 |
---|---|---|---|
1.join() |
使用不一樣的分隔符將數組轉換成包含分隔符的字符串 | 轉換後的字符串 | F |
2.reverse() |
顛倒數組元素的順序 | 重排序的數組 | T |
3.sort() |
一般會接受一個比較函數將數組特定的順序排序 | 重排序的數組 | T |
4.concat() |
將傳遞給該方法的每個參數添加到原數組中 | 修改後的數組副本 | F |
5.slice() |
獲取當前數組中的一或多個元素建立一個新的數組 | 返回新的數組 | F |
6.splice() |
經過傳遞參數不一樣,可實現數組的增刪改 | 新的數組 | T |
7.push()/pop() |
兩個數組的棧方法(後進先出),在數組的末尾增長或刪除數組 | pop() 返回數組長度,push() 返回被刪除的元素 |
T |
8.unshift()/shift() |
兩個數組的堆方法(先進先出),在數組的前端增長或刪除數組 | unshift() 返回數組長度,shift() 返回刪除的元素 |
T |
3.1 join()
方法
將數組中的全部元素都轉化爲字符串連接在一塊兒,能夠指定一個可選的分隔符來分隔各個元素,若未指定分隔符,默認使用逗號:
var boys = ['jozo','jozo1','jozo2']; var newboy1 = boys.join(); var newboy2 = boys.join('+'); var newboy3 = boys.join(undefined); console.log(newboy1); // jozo,jozo1,jozo2 console.log(newboy2); // jozo+jozo1+jozo2 console.log(newboy3); // jozo,jozo1,jozo2 console.log(boys); // ["jozo", "jozo1", "jozo2"]
從上面的代碼能夠看出一些問題:1.
給join()
方法傳遞undefined
,也會默認使用逗號分隔符,可是IE7及一下版本會直接用'undefined'
做爲分隔符。2.join()
方法並無改變原數組。
3.2 reverse()
方法
將數組元素顛倒順序(注意:並非從大到小或者是從小到大
),返回逆序的數組,這個方法直接對原數組中排序。
var a = [1,3,2]; console.log(a.reserse());// [2,3,1] 只是顛倒順序,不是按大小排序 console.log(a);//[2,3,1] 改變了原數組
這個方法快速直觀明瞭,但不夠靈活,不少時候咱們須要特定的排序,因此有了下面的更靈活的方法。
3.3 sort()
方法
默認狀況下,sort()方法按從小到大的排序,可是若是是數值,sort()方法會調用每一個元素的toString()方法轉換爲字符串後再比較:
var num = [1,5,10,15]; console.log(num.sort()); //[1,10,15,5] 按照字符串比較。 var num = ['jozo','c','b','a']; console.log(num.sort()); //['a','b','c','jozo'] 按照字符串比較。
默認的sort()方法以字母表順序進行排序,這有時也不是最佳方案,所以咱們能夠傳遞一個函數類型的參數做爲比較函數,改變排序方式,以便咱們肯定哪一個值在前面。
比較函數:接受兩個參數,函數的返回值決定數組的排序方式。
返回值 | 排序方式 |
---|---|
負數 | 從小到大 |
正數 | 從大到小 |
0 | 順序可有可無 |
看下代碼:
// 爲了直觀一點,寫個羅嗦的比較函數 var compare = function(a,b){ if(a < b){ return -1; }else if(a > b){ return 1; }else{ return 0; } }; var num1 = [1,5,10,15]; console.log(num1.sort(compare)); //[1,5,10,15] 從小到大 var num2 = ['jozo','c','b','a']; console.log(num2.sort(compare)); //['a','b','c','jozo'] 從小到大 // compare()函數能夠改進下: //從小到大的比較函數 var compare = function(a,b){ return a - b; }; //從大到小的比較函數 var compare = function(a,b){ return b - a; }; //或者直接給sort()方法傳遞一個匿名比較函數: num.sort(function(a,b){return a -b}); // 推薦用法
3.4 concat()
方法
這個方法先會建立當前數組的一個副本,而後將收到的參數添加到副本數組的末尾,返回從新構建的數組。
1.
當沒有傳遞參數時,只是返回當前數組的一個副本。
var a = [1,2]; b = a.concat(); console.log(b);//[1,2] a 的副本 console.log(a);//[1,2]; a 未改變
2.
當傳遞的參數爲非數組時,將會把每一個參數添加到副本中
var a = [1,2]; b = a.concat(3,4); console.log(b);//[1,2,3,4] 在a的副本上添加 console.log(a);//[1,2]; a 未改變
3.
當傳遞的參數是數組時,將會把數組的每個元素添加到副本中。
var a = [1,2]; b = a.concat([3,4]); console.log(b);//[1,2,3,4] 在a的副本上添加 console.log(a);//[1,2]; a 未改變 //來看看參數的另外一種形式 var a = [1,2]; b = a.concat([3,4,[5,6]]); //數組的數組 console.log(b);//[1,2,3,4,[5,6]] //數組的數組直接添加到副本 console.log(a);//[1,2]; a 未改變
3.5 slice()
方法
這個方法返回指定數組的一個片斷或子數組,接受一個或兩個參數。
1.
一個參數 :返回該參數指定位置(包含)到數組末尾的元素的新數組
var a = [1,2,3,4,5]; a.slice(0);// 返回 [1,2,3,4,5] a.slice(1);// 返回 [2,3,4,5] a.slice(7);// 返回 [] 參數超過數組索引,返回空數組 a.slice(-1);//返回 [5] 用數組長度-1 至關於slice(4); console.log(a);//返回 [1,2,3,4,5] 原數組不變
2.
兩個參數 :參數做爲始末位置,但不包含第二個參數指定的位置。
var a = [1,2,3,4,5]; a.slice(0,4);// 返回 [1,2,3,4] a.slice(1,4);// 返回 [2,3,4] a.slice(1,7);// 返回 [2,3,4,5] 參數超過數組索引,則到數組末尾 a.slice(1,-1);//返回 [2,3,4] 用數組長度-1 至關於slice(1,4); a.slice(1,-7);//返回 [] 當結束位置小於起始位置,返回空數組 console.log(a);//返回 [1,2,3,4,5] 原數組不變
3.6 splice()
方法
這個數組恐怕是數組裏最強大的方法了,它有多種用法,主要用途是向數組中部插入元素,請不要和上面的slice()方法混淆了,這是兩個徹底不一樣的方法。由參數的不一樣,可實現下列三種方法:
1.
刪除 :指定一個或兩個參數,第一個參數是刪除的起始位置,第二個參數是要刪除的元素個數,若省略第二個參數,則從起始位置刪除至末尾:
var a = [1,2,3,4,5]; a.splice(3,2);//返回 [4,5] 從索引3開始,刪除2個元素,此時 a = [1,2,3] a.splice(1);// 返回 [2,3] 此時 a = [1]
2.
插入:指定3個及以上個參數,前兩個參數和上面的一致,第二個參數通常爲0
,後面的參數表示要插入的元素:
var a = [1,2,3,4,5]; a.splice(4,0,6,7);//返回 [] 從索引4開始,刪除0個元素,此時 a = [1,2,3,4,5,6,7] //下面這種狀況又和concat()不一樣,直接插入數組而非數組元素 a.splice(4,0,[6,7]);//返回 [] 從索引4開始,刪除0個元素,此時 a = [1,2,3,4,5,[6,7]]
3.
更新:指定3個及以上個參數,前兩個參數和上面的一致,第二個參數指定要刪除的元素個數,後面的參數表示要插入的元素:
var a = [1,2,3,4,5]; a.splice(3,2,6,7);//返回 [4,5] 從索引3開始,刪除2個元素,此時 a = [1,2,3,6,7]
3.7 push()/pop()
方法
補充下數據結構的知識,棧是一種LIFO(Last-In-First-Out,後進先出)
的數據結構,也就是最新添加的項最先被移除。而棧中項的插入和移除只發生在棧頂部。數組的push(),pop()
方法就爲數組實現了相似棧的功能:
1.push():
該方法能夠接受任意數量,任意類型的的參數,並將它們添加至數組的末尾(棧頂),最後返回修改後的數組的長度
。
var a = [];// 建立空數組 var lng = a.push(1,2,3);// 添加數組元素 console.log(a);// 輸出:[1,2,3] console.log(lng);// 輸出:3 返回數組長度3 var lng2 = a.push(4,[5,6]);// console.log(lng2); // 輸出:5 返回數組長度5 console.log(a);//輸出:[1,2,3,4,[5,6]]
2.pop() :
相反,該方法刪除數組的最後一個元素,減少數組長度,並返回刪除的元素。不帶參數。
var a = [1,2,3]; var last= a.pop();// 刪除數組最後一個元素 console.log(a);// 輸出:[1,2] console.log(last);// 輸出:3 被刪除的元素是 3
能夠看出,這兩個方法都是直接修改原數組。
3.8 unshift()/shift()
方法
上面提到了棧的數據結構,這裏再提一個隊列的數據結構,這是一種FIFO(First-In-First-Out,先進先出)
的數據結構,隊列添加元素是在末端,刪除是在前端。不少同窗就會猜想了,unshift()
就是在末端添加元素,shift()
就是在前端刪除元素,其實否則:
1.shift():
用於在前端刪除數組元素,返回被刪除的元素,與push()
方法結合即是一對隊列方法。
var a = [1,2,3]; a.push(4,5);//此時 a = [1,2,3,4,5] var start = a.shift();//此時 a = [2,3,4,5] 刪除最前端的元素 console.log(start);// 1 返回刪除的元素
2.unshift():
用於在前端添加元素,返回修改後的數組的長度,與pop()方法結合即是一對反操做的隊列。
var a = [1,2,3]; a.unshift(4,5);//此時 a = [4,5,1,2,3] 在前端添加元素 var end= a.pop();//此時 a = [4,5,1,2] console.log(end);// 3 返回刪除的元素
這兩個方法一樣都是直接修改原數組。
ECMAScript定義了9個操做數組的數組方法:
遍歷:forEach()
映射:map()
過濾:filter()
檢測:every(),some()
簡化:reduce(),reduceRight()
搜索:indexOf(),lastIndexOf()
每一個方法都接受兩個參數:1.
要在每一個數組元素上運行的函數;2.
運行函數的做用域對象 -- this指向 (可選參數)
第一個參數--函數又可傳遞三個參數(簡化和搜索方法除外)
,分別表明:1.
每一個數組元素的值;2.
元素的索引;3.
數組自己
注意:全部這些方法都不會修改原始數組,可是傳遞的函數是能夠修改的。
4.1 forEach()
該方法對數組的每一項運行給定的函數。這個方法沒有返回值。
var nums = [1,2,3]; var sum = 0; nums.forEach(function(value){sum += num;}); //沒有對原數組進行修改 console.log(sum); // 6 1+2+3 nums.forEach(function(value,i,ary){ary[i] = value +1;}); //對數組進行了修改 console.log(nums);//[2,3,4]
4.2 map()
該方法對數組的每一項運行給定的函數,返回每次函數調用的結果組成的數組。
var nums = [1,2,3]; var squer = nums.map(function(value){return value*vlaue}); console.log(squer); // [1,4,9] console.log(nums);// [1,2,3]
注意:這可能看起來有點像forEach()方法,但細看會發現 該方法有返回值,而前者沒有,並且返回值是數組,這個數組是新數組,並無對原始數組進行修改。若是原始數組是稀疏數組,返回的也是相同方式的數組,具備相同的長度和相同的缺失元素。
4.3 filter()
該方法對數組的每一項運行給定的函數,返回該函數會返回true的項組成的數組。
var a = [1,2,3,4,5]; smallValue = a.filter(function(value){return value < 3;});// [1,2]
注意:filter()會跳過稀疏數組中缺乏的元素,他的返回數組老是稠密的。下面的方式能夠壓縮稀疏數組的看空缺:
var a = [1,,3,,5];//有兩個空缺元素 Var uglify = a.filter(function(){return true;}); //[1,3,5]
還能夠過濾undefined和null的元素:
var a = [1,undefined,3,,null,5];//有兩個空缺元素 Var uglify = a.filter(function(value){ return value != undefined && value != null; }); //[1,3,5]
4.4 every(),some()
every():
對數組的每一項運行給定的函數,若是該函數對數組的每一項都返回true,則返回true,注意是每一項
,有一項爲false則爲false.
var nums = [1,2,3,4,5]; var bigresult = nums.every(function(value){return value > 2}); // false 不全大於2 var result = nums.every(function(value){return value > 0}); //true 所有大於0
some():
對數組的每一項運行給定的函數,若是該函數對數組的任一項
返回true,則返回true。
var nums = [1,2,3,4,5]; var bigresult = nums.every(function(value){return value > 2}); // true 有大於2的元素 var result = nums.every(function(value){return value < 0}); //false 所有大於0
注意:在數組是空數組時,every()返回true,some()返回false
4.5 reduce(),reduceRight()
這兩個方法都會迭代數組的全部項,而後構建一個最終的返回值。reduce()從數組的第一項開始,逐個遍歷到最後;reduceRight()從數組的最後一項開始,逐個遍歷到第一項。
這兩個方法都是接收兩個參數,一個是在每項上調用的函數,另外一個是做爲遍歷的初始值。調用的函數又接收四個參數,分別是:前一個值,當前值,索引,數組對象。這個函數的返回值都會自動做爲下一次遍歷的函數的第一個參數。若未指定初始值,第一次遍歷發生在數組的第二項上,所以第一個參數就是數組第一項,第二個參數就是數組的第二項。咱們來個求和運算:
var nums = [1,2,3,4,5]; nums.reduce(function(pre,cur,index,ary){return pre + cur;}); // 15 //指定初始值,則第一個參數就是初始值,第二個參數就是數組第一項 nums.reduce(function(pre,cur,index,ary){return pre + cur;},10); 25
在簡單的數字元算上,reduce()和reduceRight()除了順序不一樣,其餘的徹底相同。
4.6 indexOf(),lastIndexOf()
這兩個方法都接受兩個參數:要查找的項,查找起點位置的索引(可選);indexOf()從數組頭部開始檢索,lastIndexOf()則從數組尾部向前開始檢索。
兩個方法都都返回找到的元素的第一次出項的位置(索引),在沒有找到的狀況下返回 -1 。
要注意的是:在檢索時會與數組的每一項進行全等的比較,也就是必須嚴格相等(===)。
var nums = [1,2,3,4,5,4,3,2,1]; console.log(nums.indexOf(3)); // 2 索引爲2 console.log(nums.lastIndexOf(3)) // 6 從後面開始找,索引爲6; console.log(nums.indexOf(3,3)); // 6 從位置3開始向後找 console.log(nums.lastIndexOf(3,3)) // 2 從位置3開始向前找 console.log(nums.indexOf(6)); // -1 沒有找到 var class= {name : 'ruanjian'}; var students = [{name : 'jozo'}]; console.log(students.indexOf(class)); //false 非嚴格相等(不是同一個對象) var school = [class]; console.log(school.indexOf(class);); //true 嚴格相等(同一個對象)
結合高級程序設計與權威指南兩本書,內容比較多,寫了好長,寫的過程當中有種以爲不必的感受,可是寫完以後就會以爲頗有價值,至少對我來講。不是我不會,而是記得不深入,從新書寫一遍以後感受對數組這東西比較透徹了。我也建議各位多作一個學習總結,若有不正確的,請提醒修正。謝謝。下一篇文章繼續介紹數組!關於ES6的一些擴展以及數組一些應用。