JavaScript——引用類型之數組

前言

以前本菜打算在寫完基本類型後寫引用類型Object的,由於Object是引用類型的基礎,其餘的引用類型也是以Object爲根本。只是關於對象的基本認識與簡單操做確實可寫的很少,打算以後與原型、原型鏈一塊兒寫。本博將介紹引用類型Array,即JavaScript中的數組。數組

Array

首先數組究竟是什麼呢?數組是一段線性分配的內存,它能經過整數計算偏移並訪問其中的元素。遺憾的是這個定義是指其餘語言中的數組,JavaScript中並無此類數據結構。做爲替代,JavaScript中基於對象建立了一種類數組的結構,它把數組的下標轉換成字符串看成屬性。這種結構雖然效率不如真正的數組,但它更加方便、靈活、強大。同時JavaScript的Array類型也是除了Object之外使用最多的。數據結構

申明

JavaScript的數組有兩種申明方式:函數

1.Array()構造函數spa

2.數組字面量3d

Array() 構造函數

使用new操做符調用Array構造函數,完成數組的實例化。code

var myArr = new Array();

在使用Array()構造函數建立新數組時也能夠傳入參數,具體有如下幾種方式:對象

1).一個參數
blog

當傳入的參數是數值時,生成一個length屬性爲該值的數組。排序

當傳入的參數不是數值時,則生成一個包含該值且length爲1的數組。 索引

2).多個參數

生成一個包含所有參數值的數組。

var arr1 = new Array(3), //[]
    arr2 = new Array("3"), //["3"]
    arr3 = new Array('red','green','blue'); //["red","green","blue"]

alert(arr1.length); //3
alert(arr1.length); //1
alert(arr1.length); //3

這裏要特別注意一點,我之因此沒有簡單的把length簡單的說成是"長度",由於JavaScript數組的length屬性嚴格上來講不該該徹底理解爲"長度",這一點以後我會解釋的。

數組字面量 

var arr = [1,3,5,7,9];

這種申明方式也是最經常使用的,它的書寫方式更加簡潔、直觀。

特色

JavaScript的數組有什麼特色呢,或者說它其餘語言的數組有什麼不一樣呢?

1.最特別的一點,JavaScript數組的每一項均可以保存不一樣的數據類型。

var myArr = [1,"hello",null,undefined,{"age":"Lily"},false]; 

如此看來JavaScript數組確實強大,它不只能夠保存不一樣類型的值,而且同一個數組中每一項的類型均可以不一樣。

同時,也能夠經過下標索引修改數組中的項

myArr[3] = "xxx"; //[1,"hello",null,"xxx",Object,false]

2.JavaScript數組的length屬性是動態可變的,包括隱式與顯式的改變方式。

隱式是指經過向數組中添加值來"撐大"數組,而顯式即爲直接設置數組的length屬性。因爲length屬性的特別,接下來詳細介紹下。

length屬性

因爲JavaScript中數組是基於對象建立的,因此length並不徹底表明其長度,應該理解爲Array這個對象的一個屬性。怎麼理解呢,例子以下。

我將以前申明的數組myArr在控制檯打印出來:

從圖中咱們能夠很清楚地看出數組即對象這個道理,所謂的索引下標實際爲對象中的屬性,只是這些屬性是以連續的數值命名的。接着往下看,咱們看到了與索引屬性並列的length屬性,以及對象特有的_proto_屬性(該屬性和對象的原型密切相關,之後咱們會討論)。

該數組咱們甚至能夠簡單的理解爲建立了以下對象:

var myArr = {
      "0": 1,
      "1": "hello",
      "2": null,
      "3": undefined,
      "4": {"age":"Lily"},
      "5": false,
      "length": 6
      .
      .
}    

有人會說討論這個有意義嗎?length值確實表明數組長度啊。那咱們經過了解如何顯式地改變length值來討論這個問題。

JavaScript數組的length屬性並非只讀的,當咱們將length變小時,多出的項會被自動截掉。

myArr.length = 3;
console.log(myArr); //[1,"hello",null]

當咱們將length值設大時,而以前問題的答案就呼之欲出了。

myArr.length = 100;

從結果圖中咱們能夠看出,雖然咱們將length值增大到100,但顯示出來的數組依然只有初始化時的6項,改變的僅僅是數組這個「對象」的某一個屬性值。

再看一個例子,若是咱們初始化一個空數組,而後增大其屬性值:

var myArr1 = new Array();
myArr1.length = 100;

能夠看到即便增大了length屬性,它依然是個空數組。

《JavaScript高級程序》中曾說過,當咱們將數組的值變大時,未初始化的項會自動用undefined值來填充。它的意思是什麼呢?

var myArr2 = [1,2,3];
myArr2.length = 5;
console.log(myArr2); //僞[1,2,3,undefined,undefined]
console.log(myArr2[3]); //undefined

它意爲當length屬性增大時,數組的項數也會同時增長,只是增長項的內容爲undefined值。但從上面兩個例子咱們能夠看出事實並不如此,索引下標沒有增長,改變的只是length屬性的值。

當執行上例中第四行代碼打印myArr2數組中第四項時,結果爲undefined。這並不意味着第四項保存着undefined值,而是根本沒有第四項。回想一下,當咱們檢索一個對象中不存在的屬性時,返回的不也是undefined嗎?就是這個道理!

那麼咱們認證了這麼多爲的是什麼?

1.數組的下標不隨length屬性的變大而自增

2.由於下標即屬性這個道理,當有人爲干預時它們極可能是不連續的!

明白以上兩點,爲的就是在運用以後數組內置方法時減小錯誤的發生。這個問題我也是在看某位大神博客中的例子發現的,理解以後我便提醒本身數組的length和長度並不徹底是一回事。

經常使用方法

因爲JavaScript數組的方法不少,這裏儘可能用最精練的語言一一介紹。

檢測

檢測一個變量是否是數組有如下兩種方法:

1.instanceof操做符,用來檢測值到底是哪一種引用類型的實例。

var arr = [1,2,3],
    value = arr instanceof Array;
alert(value); //true

2.Array.isArray()方法。因爲instanceof操做符假定單一的全局環境,爲了知足多個窗口的狀況ECMAScript5新增了該方法。

var arr = [1,2,3],
    value = Array.isArray(arr);
alert(value); //true

join()方法

以指定字符作鏈接字符,依次鏈接數組中的項並返回構成的字符串。在不傳入參數或者傳入參數爲undefined時以","拼接。

var colorArr = ["red","green","blue"];
alert(colorArr.join()); //red,green,blue
alert(colorArr.join(undefined)); //red,green,blue
alert(colorArr.join("*")); //red*green*blue

棧與隊列方法

首先說棧方法,「後進先出」。push()方法爲數組末尾添加若干項並返回新數組長度,pop()方法從數組末尾取出一項,並返回取出的項。

var colorArr = ["yellow","orange"],
    count = colorArr.push("white","black");
alert(count); //4

var item = colorArr.pop();
alert(item); //black

列方法,「先進先出」。shift()方法從數組開頭取出一項,並返回該項。配合push()方法能夠實現數組的隊列操做。

var colorArr = ["yellow","orange"],
    count = colorArr.push("white","black");
alert(count); //4

var item = colorArr.shift();
alert(item); //yellow

unshift()方法,與push()方法相似。只不過是從數組開頭添加若干項,並返回新數組長度。搭配pop()方法能夠實現數組的反向隊列操做。所說unshift()方法效率較數組其餘方法不高,因此實際中仍是慎用。

var colorArr = ["yellow","orange"],
    count = colorArr.unshift("red","green","blue");
alert(count); //5

var item = colorArr.pop();
alert(item); //orange

棧與隊列方法中這些方法的返回值該怎麼記呢?有個小技巧,若是是往數組中添加項的操做,返回的就是新數組的長度。若是是從數組中取出項的操做,那返回的就是被取出的項。是否是很好記呢?

排序方法

reverse()方法,將數組反轉排序。直觀但不夠奶靈活。 

var numArr = [1,2,3,4,5,6];
numArr.reverse();
alert(numArr); //6,5,4,3,2,1

sort()方法,用於將數組按照某種順序排列,好比遞增或遞減。

var numArr = [1,22,3,2,26];
numArr.sort();
alert(numArr); //1,2,22,26,3

從上例看出sort()方法並無按照咱們預想的進行排序,這是因爲sort()方法在默認狀況下是調用數組中每一項的toString()方法,也就是說實際比較的並非數字而是字符串,因此纔會得不到想要的結果。

爲了使其能按照預想的方式進行排序須要傳入比較函數:

function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
        return 0;
    }
}    

比較函數接收兩個參數。比較規則大概以下:當但願value1位於value2以前則返回一個負數,但願value1位於value2以後則返回一個正數,相等返回0。

var numArr = [1,22,3,2,26];
numArr.sort(compare);
alert(numArr); //1,2,3,22,26

上面的比較函數能夠比較大多數數據類型,若是要比較的只是數值的話可使用簡化版的比較函數。

function compareS(value1, value2) {
  return value1 - value2;          
}    

固然以上例子均是升序排列,降序只需調換函數中兩個參數的位置便可。

操做方法

數組的操做類方法主要有三個,splice()concat()以及slice()方法。咱們首先來介紹下splice()方法,由於它應該算是最強大的數組方法了。

splice(a,b,c)接收三個參數,a表明執行操做的位置,b表明在操做位置執行刪除操做的次數,c表明須要插入操做位置的值,能夠是多個,返回值爲刪除的數組項。根據a,b,c三個參數傳入的狀況不一樣能夠衍生出三種對數組的操做。

刪除:

var nameArr = ["Tom","Lily","Sam","Bill"],
    item = nameArr.splice(1,2);
alert(nameArr); //Tom,Bill
alert(item); //Lily,Sam

省略參數c即爲對數組的刪除操做。可是這裏要注意刪除這個過程是怎麼樣進行的,首先找到數組中位置1即"Lily",當執行一次刪除操做後本來位於位置2的"Sam"上前補位到位置1,以後執行第二次刪除操做。理解這個過程後理解插入與替換方法變得更加容易。

插入

item = nameArr.splice(1,0,"Kobe","James");
alert(nameArr); //Tom,Kobe,James,Bill
console.log(item); //空數組

令參數b爲0,即對位置1不執行刪除操做,只插入"Kobe","James"兩項。

替換:

item = nameArr.splice(2,2,"Fanfan");
alert(nameArr); //Tom,Kobe,Fanfan
alert(item); //James,Bill

先對位置2進行兩次刪除操做,移除並返回"James","Bill"兩項,而後在位置2添加"Fanfan"。

當徹底理解了splice()方法後,就能夠把它當成一種操做。分紅三種只是方便理解。

concat()方法,用於基於當前數組建立一個新數組。簡單來講就是首先建立原數組的一個副本,而後將接收的參數添加到數組末尾,返回新數組。

var arr = [1,2,3],
    arr2 = arr.concat([4,5]),
    arr3 = arr.concat(6,7),
    arr4 = arr.concat(8,[9,10]);
alert(arr); //1,2,3
alert(arr2); //1,2,3,4,5
alert(arr3); //1,2,3,6,7
alert(arr4); //1,2,3,8,9,10

從上例能夠看出,傳入的參數不管是單獨的值仍是數組或者兩者混合,均可以拼接成新數組。

slice()方法,基於當前數組中的若干項建立一個新的子數組。接收兩個參數,第一個參數爲起始位置,第二個參數爲結束位置。返回從起始位置到結束位置前一項組成的數組,若是不指定結束位則到數組末尾。

var arr = [1,2,3,4,5,6,7,8,9,10],
    arr2 = arr.slice(3),
    arr3 = arr.slice(3,8);
alert(arr); //1,2,3,4,5,6,7,8,9,10
alert(arr2); //4,5,6,7,8,9,10
alert(arr3); //4,5,6,7,8

感謝您的瀏覽,但願能對您有所幫助。

相關文章
相關標籤/搜索