[ JS 基礎 ] Array 對象全面解析 -- 掌握基礎 ( 4 )

結合《javascript高級程序設計》《javascript權威指南》《javascript語言精粹》作的一篇關於Array對象的全面解析。分爲兩篇:基礎篇和擴展應用篇。javascript

1.概念及特色

數組是值的有序集合,每一個值稱爲一個元素,每一個元素在數組中有特定位置,以數字表示,稱爲索引,JavaScript中的數組是一個類數組的對象,雖然在性能上比真正的數組會慢,但它使用起來更方便。
前端

特色 說明
元素類型任意性 數組元素能夠是基礎數據類型,對象,也能夠是數組
動態性 根據須要它們會增加或縮減,而且在變化時無需從新分配內存空間
稀疏性 數組元素的索引不必定是連續的,它們之間能夠有空缺,

2.建立方式

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.添加與刪除

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);//輸出: []

3.經常使用方法屬性詳解

其實上面的知識點不講咱們都差很少都知道的。可是數組的一些方法屬性咱們雖然知道可是卻不會用,或是老是忘記該怎麼用,由於它的方法屬性也不少,咱們來分析下各個方法的特色:

經常使用方法 說明 返回值 影響原數組
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 返回刪除的元素

這兩個方法一樣都是直接修改原數組。

4.ES5的數組方法

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

clipboard.png

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 嚴格相等(同一個對象)

5.總結

結合高級程序設計與權威指南兩本書,內容比較多,寫了好長,寫的過程當中有種以爲不必的感受,可是寫完以後就會以爲頗有價值,至少對我來講。不是我不會,而是記得不深入,從新書寫一遍以後感受對數組這東西比較透徹了。我也建議各位多作一個學習總結,若有不正確的,請提醒修正。謝謝。下一篇文章繼續介紹數組!關於ES6的一些擴展以及數組一些應用。

相關文章
相關標籤/搜索