JavaScript——參考型別之數組

來源:互聯網
上載者:User

標籤:

前言

之前本菜打算在寫完基本類型後寫參考型別Object的,因為Object是參考型別的基礎,其他的參考型別也是以Object為根本。只是關於對象的基本認識與簡單操作確實可寫的不多,打算之後與原型、原型鏈一起寫。本博將介紹參考型別Array,即JavaScript中的數組。

Array

首先數組到底是什麼呢?數組是一段線性分配的記憶體,它能通過整數計算位移並訪問其中的元素。遺憾的是這個定義是指其他語言中的數組,JavaScript中並沒有此類資料結構。作為替代,JavaScript中基於對象建立了一種類數組的結構,它把數組的下標轉換成字串當作屬性。這種結構雖然效率不如真正的數組,但它更加方便、靈活、強大。同時JavaScript的Array類型也是除了Object以外使用最多的。

申明

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

1.Array()建構函式

2.數組字面量

Array() 建構函式

使用new操作符調用Array建構函式,完成數組的執行個體化。

var myArr = new Array();

在使用Array()建構函式建立新數組時也可以傳入參數,具體有以下幾種方式:

1).一個參數

當傳入的參數是數值時,產生一個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); //3alert(arr1.length); //1alert(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,bluealert(colorArr.join(undefined)); //red,green,bluealert(colorArr.join("*")); //red*green*blue
棧與隊列方法

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

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

隊列方法,“先進先出”。shift()方法從數組開頭取出一項,並返回該項。配合push()方法可以實現數組的隊列操作。

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

unshift()方法,與push()方法類似。只不過是從數組開頭添加若干項,並返回新數組長度。搭配pop()方法可以實現數組的反向隊列操作。所說unshift()方法效率較數組其他方法不高,所以實際中還是慎用。

var colorArr = ["yellow","orange"],    count = colorArr.unshift("red","green","blue");alert(count); //5var 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();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,Billalert(item); //Lily,Sam

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

插入:

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

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

替換:

item = nameArr.splice(2,2,"Fanfan");alert(nameArr); //Tom,Kobe,Fanfanalert(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,3alert(arr2); //1,2,3,4,5alert(arr3); //1,2,3,6,7alert(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,10alert(arr2); //4,5,6,7,8,9,10alert(arr3); //4,5,6,7,8
感謝您的瀏覽,希望能對您有所協助。

JavaScript——參考型別之數組

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.