JavaScript之數組

概念

JavaScript數組是JavaScript對象的特殊形式。數組索引實際上和碰巧是整數的屬性名差很少,使用方括號訪問數組元素就像用方括號訪問對象的屬性同樣。JavaScript將指定的數字索引值轉換成字符串——索引值1變成 「1」——而後將其做爲屬性名來使用。javascript

數組的特別之處在於,當使用小於2^32的非負整數做爲屬性名時數組會自動維護其length屬性值。一般,數組的實現是通過優化的,用數字索引來訪問數組元素通常來講比訪問常規的對象屬性要快不少。前端

注意,可使用負數或非整數來索引數組。這種狀況下,數值轉換爲字符串,字符串做爲屬性名來用。java

數組相關函數

數組遍歷方法

  1. for循環
  2. Array.prototype.forEach()
    forEach() 方法用於調用數組的每一個元素,並將元素傳遞給回調函數。沒有返回值node

    array.forEach(callback(currentValue[, index, array]]), [thisArg])

    實例:遍歷並輸出全部數組元素算法

    function logArrayElements(element, index, array) {
      console.log('a[' + index + '] = ' + element);
    }
    
    // 注意索引 2 被跳過了,由於在數組的這個位置沒有項
    [2, 5, , 9].forEach(logArrayElements);
    // logs:
    // a[0] = 2
    // a[1] = 5
    // a[3] = 9
  3. Array.prototype.map()
    map() 方法返回一個新數組,數組中的元素爲原始數組元素調用函數處理後的值,不改變原數組json

    var newArray = arr.map(callback(currentValue[, index[, array]]) {
        // Return element for new_array 
    }[, thisArg]);

    實例1: 求數組中每一個元素的平方根segmentfault

    var numbers = [1, 4, 9];
    var roots = numbers.map(Math.sqrt);
    // roots的值爲[1, 2, 3], numbers的值仍爲[1, 4, 9]

    實例2:在一個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]
  4. Array.prototype.filter()
    filter()方法建立一個新數組,返回一個新的、由經過測試的元素組成的數組,若是沒有任何數組元素經過測試,則返回空數組。promise

    var newArray = array.filter(callback(element[, index[, array]])[, thisArg])

    實例:使用filter()建立具備非零id的元素的 json。app

    var arr = [
      { id: 15 },
      { id: -1 },
      { id: 0 },
      { id: 3 },
      { id: 12.2 },
      { },
      { id: null },
      { id: NaN },
      { id: 'undefined' }
    ];
    
    // 判斷當前元素是否爲數字
    function isNumber(obj) {
      return obj !== undefined && typeof(obj) === 'number' && !isNaN(obj);
    }
    //callback過濾函數
    function filterByID(item) {
      if (isNumber(item.id) && item.id !== 0) {
        return true;
      } 
      invalidEntries++;
      return false; 
    }
    
    var arrByID = arr.filter(filterByID);
    // Filtered Array:
    // [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]
  5. Array.prototype.reduce()
    方法對數組中的每一個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總爲單個返回值。
    語法:

    var result = array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

    reduce爲數組中的每個元素依次執行callback函數,不包括數組中被刪除或從未被賦值的元素,接受四個參數:

    accumulator 累計器
    currentValue 當前值
    currentIndex 當前索引
    array 數組

    回調函數第一次執行時,accumulator和currentValue的取值有幾種狀況:
    若是調用reduce()時提供了initialValue,accumulator取值爲initialValue,currentValue取數組中的第一個值;
    若是沒有提供initialValue,那麼accumulator取數組中的第一個值,currentValue取數組中的第二個值。
    若是數組爲空且沒有提供initialValue,會拋出TypeError。
    若是數組僅有一個元素(不管位置如何)而且沒有提供initialValue, 或者有提供initialValue可是數組爲空,那麼此惟一值將被返回而且callback不會被執行。

    reduce()如何運行:
    假如運行下段reduce()代碼:

    [0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array){
      return accumulator + currentValue;
    });

    Callback 被調用四次,每次調用的參數和返回值以下表:
    圖片描述
    您還能夠提供Arrow Function來代替完整的函數。 下面的代碼將產生與上面的代碼中相同的輸出:

    [0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr );

    若是你打算提供一個初始值做爲reduce()方法的第二個參數,如下是運行過程及結果:

    [0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { returnaccumulator+ currentValue; }, 10);    // =>20

    實例1:計算數組中每一個元素出現的次數

    var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
    var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
    var countedNames = names.reduce(function (allNames, name) { 
      if (name in allNames) {
        allNames[name]++;
      }
      else {
        allNames[name] = 1;
      }
      return allNames;
    }, {});
    // countedNames is:
    // { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

    實例2: 數組去重

    let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
    let result = arr.sort().reduce(function(init, currentValue){
        if(init.length === 0 || init[init.length - 1] !== currentValue){
        init.push(current);
      }
        return init;
    }, []);    // => [1, 2, 3, 4, 5]
    此處額外附上其餘數組去重方法以做對比參考
    // 方法一
    var norepeat = funtion(arr){
        return arr.filter(function(val, index, array){
            return array.indexOf(val) === index;
        });
    }
    norepeat()
    
    // 方法二
    var set = new Set(arr);

    實例3:按順序運行Promise

    // Runs promises from array of functions that can return promises
     // in chained manner
     // @param {array} arr - promise arr
     // @return {Object} promise object
     
    function runPromiseInSequence(arr, input) {
      return arr.reduce(
        (promiseChain, currentFunction) => promiseChain.then(currentFunction),
        Promise.resolve(input)
      );
    }
    
    // promise function 1
    function p1(a) {
      return new Promise((resolve, reject) => {
        resolve(a * 5);
      });
    }
    
    // promise function 2
    function p2(a) {
      return new Promise((resolve, reject) => {
        resolve(a * 2);
      });
    }
    
    // function 3  - will be wrapped in a resolved promise by .then()
    function f3(a) {
     return a * 3;
    }
    
    // promise function 4
    function p4(a) {
      return new Promise((resolve, reject) => {
        resolve(a * 4);
      });
    }
    
    const promiseArr = [p1, p2, f3, p4];
    runPromiseInSequence(promiseArr, 10)
      .then(console.log);   // 1200
  6. Array.prototype.some()Array.prototype.every()

    some()方法測試是否至少有一個元素能夠經過被提供的函數方法。該方法返回一個Boolean類型的值。some()被調用時不會改變數組

    array.some(callback(element[, index[, array]])[, thisArg])

    實例:檢測在數組中是否有元素大於 10。

    function isBiggerThan10(element, index, array) {
      return element > 10;
    }
    
    [2, 5, 8, 1, 4].some(isBiggerThan10);  // false
    [12, 5, 8, 1, 4].some(isBiggerThan10); // true

    every()方法就像數學中的「針對全部」的量詞,當且僅當針對數組中的全部元素調用斷定函數都返回true,它才返回true。和some有類似之處。
    實例:

    a = [1,2,3,4,5];
    a.every(function(x) { return X < 10; }) // => true:全部的值<10
    a.every(function(x) { return x % 2 === 0; }) // => false: 不是全部的值都是偶數

js數組方法

  1. Array.prototype.push()Array.prototype.pop()

    push()方法向數組的末尾添加一個或更多元素,並返回新的長度。
    pop()方法刪除並返回數組的最後一個元素。

  2. Array.prototype.unshift()Array.prototype.shift()

    shift()方法刪除並返回數組的第一個元素。
    unshift()方法向數組的頭部添加一個或更多元素,並返回新的長度。

    注意,當使用多個參數調用unshift()時它的行爲使人驚訝。參數是一次性插入的(就像splice()方法)而非一次一個地插入。這意味着最終的數組中插入的元素的順序和它們在參數列表中的順序-致。而假如元素是一次一個地插入,它們的順序應該是反過來的。

  3. Array.prototype.reverse()

    方法將數組中元素的位置顛倒,並返回該數組。reverse()方法會改變原數組

  4. Array.prototype.sort()
    方法用原地算法對數組的元素進行排序,並返回數組。排序算法如今是穩定的。默認排序順序是根據字符串Unicode碼點。因爲它取決於具體實現,所以沒法保證排序的時間和空間複雜性。sort()原數組上原地排序,會致使原數組改變

    var a = [33, 4, 1111, 222];
    a.sort();
    //字母表順序: 1111,222,33,4
    a.sort(function(a, b) {    // =>a: [4, 33, 222, 1111]
    return a - b;    // 根據順序,返回負數、0、正數
    });
    a.sort( function(a, b) {return b - a});    // =>a: [1111, 222, 33, 4]
  5. Array.prototype.concat(array2)
    方法用於合併兩個或多個數組。concat()方法不會更改原數組,而是返回一個新數組
  6. Array.prototype.join()
    方法將數組中全部元素都轉化爲字符串並鏈接在一塊兒,返回最後生成的字符串。能夠指定一個可選的字符串在生成的字符串中來分隔數組的各個元素。若是不指定分隔符,默認使用逗號。join()方法不應變原數組。
    實例:字符串數組鏈接成字符串

    var arr = new Array(3)
    arr[0] = "George"
    arr[1] = "John"
    arr[2] = "Thomas"
    arr.join()
    // output: George,John,Thomas
  7. Array.prototype.slice(start, end)

    slice()方法返回指定數組的一個片斷或子數組。它的兩個參數分別指定了片斷的開始和結束的位置。返回的數組包含第一個參數指定的位置和全部到但不含第二個參數指定的位置之間的全部數組元素。若是隻指定一個參數,返回的數組將包含從開始位置到數組結尾的全部元素。如參數中出現負數,它表示相對於數組中最後一個元素的位置。slice()方法不會改變原數組

    // 語法:
    str.slice(beginSlice[, endSlice])
    
    beginSlice:
    必需。規定從何處開始選取。若是是負數,那麼它規定從數組尾部開始算起的位置。也就是說,-1 指最後一個元素,-2 指倒數第二個元素,以此類推。
    
    endSlice:
    可選。規定從何處結束選取。該參數是數組片段結束處的數組下標。若是沒有指定該參數,那麼切分的數組包含從 start 到數組結束的全部元素。若是這個參數是負數,那麼它規定的是從數組尾部開始算起的元素。
    
    //實例: 
    var arr = new Array(3)
    arr[0] = "George"
    arr[1] = "John"
    arr[2] = "Thomas"
    arr.slice(1) // output: John,Thomas
  8. Array.prototype.splice() :方法經過刪除或替換現有元素或者原地添加新的元素來修改數組,並以數組形式返回被修改的內容。此方法會改變原數組
    語法:

    array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

    實例:

    // 示例1: 添加元素
    var fruits = ["Banana", "Orange", "Apple", "Mango"];
    fruits.splice(2,1,"Lemon","Kiwi");    // output: Banana,Orange,Lemon,Kiwi,Mango
    
    // 示例2: 刪除元素
    var fruits = ["Banana", "Orange", "Apple", "Mango"];
    fruits.splice(2,2);    // output: Banana,Orange
  9. Array.prototype.indexOf()Array.prototype.lastIndexOf()
    index0f()和lastIndex0f()搜索整個數組中具備給定值的元素,返回找到的第一個元素的索引或者若是沒有找到就返回-1。index0f( )從頭到尾搜索,而lastIndexOf()則反向搜索。
  10. Array.prototype.reduce(reducer)
    方法對數組中的每一個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總爲單個返回值
  11. Array.prototype.map():對數組的每一項應用回調函數,返回新數組
  12. Array.prototype.some():數組中只需有一項知足給定條件則返回true。
  13. Array.prototype.every():數組的每一項都知足給定條件則返回true。
  14. Array.prototype.filter():方法建立一個新數組, 其包含經過所提供函數實現的測試的全部元素。
  15. Array.prototype.forEach():數組遍歷,與for循環同樣,沒有返回值

數組類型

給定一個未知的對象,斷定它是否爲數組一般很是有用。在ECMAScript 5中,可使用Array.isArray()函數來作這件事情:

Array.isArray([]) //=>true
Array.isArray({}) // => false

在ECMAScript 3中isArray( )函數的代碼能夠這樣書寫:

var isArray = Function.isArray || function(o) {
return typeof o === "object" && Object.prototype.toString. call(o) === "[object Array]";
};

類數組對象

咱們已經看到,JavaScript數組的有- - 些特性是其餘對象所沒有的:

* 當有新的元素添加到列表中時,自動更新length屬性。
* 設置length爲一個較小值將截斷數組。
* 從Array.prototype中繼承一些有用的方法。
* 其類屬性爲「Array' 。

這些特性讓JavaScript數組和常規的對象有明顯的區別。可是它們不是定義數組的本質特性。一種經常徹底合理的見解把擁有-個數值length屬性和對應非負整數屬性的對象看作一種類型的數組。

實例:爲一個常規對象增長了一些屬性使其變成類數組對象,而後遍歷生成的僞數組的「元素」:

var a = {};    // 從一個常規空對象開始
// 添加一些屬性,稱爲"類數組"
var i = 0;
while(i < 10) {
    a[i] = i * i;
    i++;
}
a.length = i;
// 如今,當作真正的數組遍歷它
var total = 0;
for(var j = 0; j < a.length; j++)
total += a[j] ;    // => 287

JavaScript中的Arguments對象就是一個類數組對象。一些DOM方法(如document.getElementsByTagName()也返回類數組對象。
下面有一個函數能夠用來檢測類數組對象:

//斷定o是不是一個類數組對象
//字符串和函數有length屬性,可是它們
//能夠用typeof檢測將其排除。在客戶端JavaScript中,DOM文 本節點
//也有length屬性,須要用額外判斷o. nodeType != 3將其排除
function isArrayLike(o) {
  return o && typeof o === "object" && isFinite(o.length) && o.length >= 0 && o.length === Math.floor(o.length) && o.length < 4294967296;             
}

參考:

* 《JavaScript權威指南》第六版
* [MDN Web 文檔](https://developer.mozilla.org/zh-CN/)

推薦閱讀:
【專題:JavaScript進階之路】
JavaScript之「use strict」
JavaScript之new運算符
JavaScript之call()理解
JavaScript之對象屬性


我是Cloudy,年輕的前端攻城獅一枚,愛專研,愛技術,愛分享。
我的筆記,整理不易,感謝閱讀、點贊和收藏。
文章有任何問題歡迎你們指出,也歡迎你們一塊兒交流前端各類問題!
相關文章
相關標籤/搜索