最詳細的JavaScript高級教程(九)Array

Array類型是js中常用的引用類型。js中的Array最大的特點就是:數組可以容納多種類型的元素,數組在定義的時候不用指明元素類型,一個數組中可以混雜多種數據類型。

創建數組

// 使用Array對象初始化
// 需要預先知道元素數量
var colors = new Array(10);
// 傳入數字,則使用數字個數初始化數組
// 傳入其他數據類型,則創建只有一個元素的數組
var colors = new Array('red');
// 使用多個元素初始化Array
var colors = new Array('red', 'blue', 'green');
// 省略new
var colors = Array(34);


// 使用字面量
var colors = ['red'];
// 創建空數組
var colors = [];
// 使用下面的寫法在不同的瀏覽器中運行結果不同,不要使用
var colors = ['red'];
var colors = [, ,];

使用數組

數組可以自動擴充,當設置了數組之外的索引的值的時候,數組被自動擴充到需要的大小

var colors = new Array('red', 'blue', 'green');
console.log(colors.length); // 3
console.log(colors[5]); // 輸出undefined
console.log(colors.length); // 3
colors[5] = '6';
console.log(colors.length); // 6

數組的length不是隻讀的,所以可以用於刪除項或者新增項,新增的項都是undefined,數組的這個特性還有個很巧妙的用法就是用來添加新的項

// 裁切數組
var colors = new Array('red', 'blue', 'green');
colors.length = 2;
console.log(colors[2]); // undefined
// 在數組後追加一項
colors[colors.length] = 'new';
colors[colors.length] = 'new2'; // 再新增一項

檢測對象是不是數組

當我們檢測一個對象是不是數組的時候很容易想到使用 instanceof 來判斷。我們複習一下 instanceof 是判斷一個對象的原型的,我們通過判斷對象是不是繼承自Array就可以判斷出來。

但是,這只是理論上可行,由於網頁的運行環境複雜,很容易就包含多個框架,而多個框架就有可能有多個Array的構造函數,如果兩個框架之間傳遞參數,就有可能判斷有誤,認爲這個對象並不是繼承自自己框架內的Array,導致判斷失誤。

正確的做法是使用ES5提供的Array.isArray方法

var colors = new Array('red', 'blue', 'green');
console.log(Array.isArray(colors)); // true
console.log(Array.isArray('123'));  // false

數組的輸出

數組默認tostring是以逗號分隔輸出的。

var colors = new Array('red', 'blue', 'green', null, undefined);
console.log(colors); //'red', 'blue', 'green', null, undefined 

當我們不想用逗號分隔,想用別的標識符分隔的時候,使用join函數

var colors = new Array('red', 'blue', 'green', null, undefined);
console.log(colors.join('|')); //red|blue|green||

注意當數組中有null和undefined的時候,不同環境的處理不同,node中會打印出null和undefined,在瀏覽器中都顯示空字符串,而使用join,null和undefined都會轉化爲空字符串顯示。

棧和隊列

在js中,想使用棧和隊列不需要再定義新的數據結構,使用數組即可,使用push入棧,使用pop彈出棧,使用shift出隊列,有了這三個方法,我們就可以模擬入棧出棧,入隊列出隊列了

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.push('p');  // 入棧
console.log(colors.pop());  // 出棧,輸出p

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.push('p');
console.log(colors.shift()); //red,從隊列頭彈出一個元素

但是,如果我們想實現一個相反的隊列怎麼辦,從隊列頭進隊列,從尾部消費。這時候我們需要用unshift像隊列頭添加元素,使用pop消費即可。

var colors = new Array('red', 'blue', 'green', null, undefined);
colors.unshift('1');  // 在數組的頭部添加一個元素
console.log(colors.pop()); //從尾部彈出undefined

入站,入隊列這種給數組添加值的方法有返回值,其返回值是數組變更之後數組的長度。

排序

使用reverse方法反轉數組順序

var values = [0, 1, 15, 5, 10];
console.log(values.reverse()); // 10, 5, 15, 1, 0

使用sort可以更精確的排序,不添加參數它默認從小到大按照字符串順序排序,這種方法會把 10 排到 5前面,不太好用,我們一般使用的時候給它傳遞一個函數進去來告訴它應該如何排序

var values = [0, 1, 15, 5, 10];
// 從大到小排列
function compare(value1, value2) {
  if (value1 < value2) {
    return 1;
  } else if (value1 > value2) {
    return -1;
  } else {
    return 0;
  }
}
// compare函數可以改寫爲
function compare2(value1, value2) {
  return value2 - value1;
}
// 注意sort方法會返回排序之後的數組
console.log(values.sort(compare)); //15, 10, 5, 1, 0

拼接多個數組

使用concat方法拼接數組,這個方法十分的靈活,可以傳遞一個對象,也可以傳遞一個數組,注意不是在原數組上進行拼接,而是返回一個新的數組

var a = [1];
var b = a.concat(2, [3, 4]);
console.log(b); //1, 2, 3, 4

切片

使用slice方法對於數組進行切片,注意切片這個函數的行爲,主要有下面幾點

  • 與concat方法一樣,這個方法不修改原數組,返回一個新的數組
  • 傳入一個參數,則指定了切片的起始位置,是從當前位置,一直切到結束
  • 傳入兩個參數,第二個參數指示結束位置,結束位置的元素不會被切出來
  • 當起始座標大於結束座標,返回空數組
  • 當參數位負數,使用length加上這個負數就是真正需要的值
var a = [1, 2, 3, 4];
console.log(a.slice(1, 3)); //2, 3 不包括位置爲3的元素
console.log(a.slice(-1)); //4  length是4,4-1=3則從第三個元素截取到最後
console.log(a.slice(2, 1)); //空數組

刪除,插入和替換

使用splice來完成這一系列複雜的操作,需要特別注意的是,splice方法會修改原數組,他的返回值是:如果有刪除的項則返回刪除的項

  • 刪除,指定兩個參數,第一個是起始位置,第二個是要刪除的個數
  • 插入,指定3+個參數,第一個是起始位置,第二個刪除個數填0,不刪除,後面的參數填要插入的值,可以插入多個
  • 替換,指定3+個參數,第二個刪除的值填寫要被替換的值,可以刪除一個添加多個,以達到替換的效果
var a = [1, 2, 3, 4];
// 刪除第二個值
console.log(a.splice(1, 1)); // [2] 刪除的項目,放到數組中返回
console.log(a); //1, 3, 4
var a = [1, 2, 3, 4];
// 插入
console.log(a.splice(1, 0, 9)); // 刪除的項目,空數組
console.log(a); //1, 2, 9, 3, 4
var a = [1, 2, 3, 4];
// 替換
console.log(a.splice(1, 1, 9)); // 刪除的項目,[2]
console.log(a); //1, 9, 3, 4

位置查找方法

再js中查找一個元素的位置的方法有兩個

  • indexOf 從前往後查找
  • lastIndexOf 從後往前查找

他們的參數:第一個是要查找的元素,與數組中元素進行全等比較,第二個是可選參數,可以指定開始查找的位置

var a = [1, 2, 3, 4, 1];
alert(a.lastIndexOf(1, 3)); // 輸出0, 從下標爲3的元素向前查找1

迭代方法

很多時候我們需要將數組中的元素一一進行某些運算,這時候我們就要用到迭代方法。下面介紹所有的迭代方法,需要注意:

  • 迭代方法的參數都是一個方法,這個方法指示了要對數組中的元素做哪些操作
  • 所有的迭代方法都不會修改原數組中的值
  • 傳入的方法有三個參數 第一個是該元素的字面值 第二個是該元素在數組中的位置 第三個是這個數組本身
    介紹迭代方法:
  • every 對數組中每一項都運行,如果每一項都返回true則結果爲true。實際意義是判斷所有的項都滿足某個條件。
  • some 對數組中每一項都運行,如果其中一個返回true則運行結果爲true。這個方法的實際意義是檢測有沒有一個元素滿足某個條件
  • forEach 對數組中每一項都運行某個函數,沒有返回值
  • map 對數組中每一項都運行某個函數,返回執行結果組成的數組
  • filter 對數組中每一項都運行某個函數,返回值爲true的元素組成返回值返回
var a = [1, 2, 3, 4, 1];
var result = a.every(function(item, index, array){
    return item > 2; // 判斷是不是所有的元素都大於2
});
alert(result);  // false
var a = [1, 2, 3, 4, 1];
var result = a.some(function(item, index, array){
    return item > 2; // 判斷有沒有元素大於2
});
alert(result);  // true
var a = [1, 2, 3, 4, 1];
var result = a.filter(function(item, index, array){
    return item > 2; // 過濾出大於2的元素
});
alert(result);  // 3, 4
var a = [1, 2, 3, 4, 1];
var result = a.map(function(item, index, array){
    return item * 2; // 所有的元素乘2返回數據
});
alert(result);  // 2, 4, 6, 8, 2
// 獲取所有元素之和
// 只用數組的值,不用返回每次運行的值
var a = [1, 2, 3, 4, 1];
var sum = 0;
var result = a.forEach(function(item, index, array){
    sum += item;
});
alert(sum);  // 11

歸併函數

js中的歸併函數有reduce和reduceRight兩個,區別顯而易見,reduce是從左往右歸併,後者是從右向左歸併。

所謂歸併函數,就是給出一個函數,數組中的值帶入進行運算,運算的結果帶入下一次運算繼續運算。常用的地方是:

  • 數組求和
  • 數組求最大值
  • 數組去重
// 獲取所有元素之和
var a = [1, 2, 3, 4, 1];
var result = a.reduce((para1, para2, index, array)=>{
    return para1 + para2;
});
alert(result); // 11
// 獲取所有元素最大值
var a = [1, 2, 3, 4, 1];
var result = a.reduce((para1, para2, index, array)=>{
    return Math.max(para1, para2);
});
alert(result); //4
// 數組去重
var a = [1, 2, 3, 4, 1];
var result = a.reduce((prev, cur)=>{
    prev.indexOf(cur) === -1 && prev.push(cur);
    return prev;
}, []);
alert(result); //4

注意在去重的例子中,我們給reduce傳入了第二個參數,這個參數指示了reduce運行的時候prev的初始值是什麼,這樣極大的擴展了reduce的用處。

注意

  • 數組最大可以包含 4294967295 個值,這個值非常大以至於我們一般不會考慮數組不夠用的情況

ES6 - 解構賦值

在解構賦值出現之前,我們想把一個數組中的值分別賦值給幾個變量,以前只能一個一個賦值,現在可以使用解構賦值。

解構賦值就是模式匹配,把相同位置的值賦值給相同位置的變量。

數組解構賦值的語法是:賦值等號的左邊要使用數組包起來,右邊要傳一個可以迭代的對象。

在我們使用解構賦值的時候只需要下面幾個原則:

  • 如果需要賦值的變量比提供的值多,沒提供的值都是undefined
    let [a, b, c] = [1, 2];
    alert(a); //1
    alert(b); //2
    alert(c); //undefined
    
  • 如果需要賦值的變量比提供的值少,不會有影響
    let [a, b] = [1, 2, 3];
    alert(a); //1
    alert(b); //2
    
  • 數組裏面可以嵌套數組,位置對應上就可以賦值
    let [a, [b, c]] = [1, [2, 3]];
    alert(a); //1
    alert(b); //2
    alert(c); //3
    
  • 如果對象本身就是數組,需要使用…來賦值
    let [a, ...b] = [1, 2, 3]; //想給b賦值爲[2, 3]
    alert(a); //1
    alert(b); //[2, 3]
    
  • 等號的右邊不一定是需要數組,只要是可以遍歷的就可以
    let [first, second, third, fourth, fifth, sixth] = fibs();
    alert(first); //0
    alert(second); // 1
    alert(third); // 1
    alert(fourth); // 2
    alert(fifth); // 3
    alert(sixth); // 5
    
  • 等號右邊如果不是可以遍歷的就會報錯
    let [a] = false; //報錯 false is not iterable
    
  • 可以設置默認值以防止解構賦值失敗,需要注意,只有變量等於undeifined的時候,纔會觸發默認值,null不會觸發默認值
    // 設置默認值
    let [a, b = '1'] = ['w'];
    alert(a); //w
    alert(b); //1
    
    // null不會觸發默認值
    let [a = 'w', b = '1'] = [undefined, null];
    alert(a); //w
    alert(b); //null
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章