天天看點

林大媽的JavaScript基礎知識(三):JavaScript程式設計(4)數組

  數組,是一段線性配置設定的,具有非常高性能的資料結構。簡單地說,數組以連續的空間存儲,通過整數地計算偏移量通路其中的元素,将讀取修改的時間複雜度降低至O(1),我們稱之為猝發式存取。是不是非常期待?沒錯,像這樣的好東西,JavaScript沒有。

1. Array簡介

  但作為替代,JavaScript設計者想出了一個更友善但性能相對較低的方案,列印觀察Array.prototype,會發現,設計者為我們提供的是一個array-like(類數組)的對象。在檢索和更新屬性上,Array就和普通的對象一模一樣(也就是說要周遊所有屬性),隻是多了一個不可枚舉的屬性length來記錄這個對象所表示的數組的長度。盡管Array對象的性能明顯比數組要差,但是搭配上弱類型的JavaScript語言(當然,JavaScript中不存在傳統的數組一部分原因也是因為這一點),它在使用上非常的友善。更貼心的是,設計者還為我們提供了許多内置的方法,可以快速解決其他語言費很大勁才能解決的問題。

2. 聲明

  數組的聲明跟對象的聲明很類似。我們可以用兩種方法初始化一個數組:① 直接用 var array = []; 我們稱之為數組字面量的方式來初始化;② 使用構造函數 var array = new Array(); 如果參數填入一個數字,則傳回一個長度為這個數字的空數組,如果參數填入多個值,則傳回一個按順序儲存了這些值的Array對象。

3. 修改

  上面我們已經搞清楚了Array對象總體的結構,這樣修改一個數組就可以轉化為我們以前學到的修改一個對象屬性的知識了。由于JavaScript的靈活性,除非你定義一個大到Infinity的數組,其他情況下均不會因為越界報錯(Runtime Error也許是很多人的噩夢,反正是我的噩夢)。是以,假如我們現在有這樣一個數組:

1 var myArray = [0, '1', true]      

  利用JavaScript會幫我們維護length屬性這一特點(但為了編寫易維護的代碼,不推薦這些簡單粗暴的做法),我們也可以做一些在别的語言中看起來不可思議的操作,例如:① myArray[8] = undefined 會直接把Array的長度擴充到8;②  myArray.length = 0; 能直接清空數組。除了可以這樣清空數組,還可以通過Array.prototype.splice方法完成清空,是以我們把目光放到數組的原型方法上來。

4. 原型方法(均以上面的myArray舉例)

  ① indexOf

   indexOf方法同時存在于Array.prototype和String.prototype中,可以用它來檢測數組或字元串中是否存在對應的元素,如果存在,則傳回它的下标,如果不存在,則傳回-1:

1 console.log(myArray.indexOf(0)); //0
2 console.log(myArray.indexOf(1)); //-1      

   由于在數組中,1和'1'是兩個不同的值,是以第二句傳回結果-1。

  ② push、pop、unshift、shift

   push朝數組末尾推入若幹新元素,傳回加入後數組的length。

   pop彈出數組末尾的一個元素,傳回被彈出的元素。

   unshift朝數組開頭推入若幹新元素,傳回加入後數組的length。

   shift彈出數組開頭的一個元素,傳回被彈出的元素。

1 console.log(myArray.push('A', 'B')); //5
2 console.log(myArray.pop()); //'B'
3 console.log(myArray.unshift('A', 'B')); //6
4 console.log(myArray.shift()); //'A'      

  ③ sort(這時候我們重新定義一下 myArray = [5, 2, 0, 10, 17, 25]; )

   sort方法在原數組上動刀,這裡我們期望将數組中的數按從小到大的順序排列,sort函數可以幫我們做到這一點,但需要注意的是,sort函數預設把這些元素轉化為字元串進行比較。是以這個數組排序以後的結果是這樣的:

1 console.log(myArray.sort()); // [0, 10, 17, 2, 25, 5]      

   是以通常需要填入一個比較判斷函數作為參數,下面傳入一個箭頭函數,按照我所定義的這個函數進行判斷大小再排序:

1 console.log(myArray.sort((x, y)=>{return x - y;})); // [0, 2, 5, 10, 17, 25]      

  ④ reverse和join

   reverse方法在原數組上動刀,傳回跟原來相反的數組;join方法相當于String.prototype.split方法的反函數,填入一個字元串參數,以這個參數将每個元素分隔開,合并成一個字元串并傳回。這兩個方法可以搭配使用來處理反向輸出字元串的問題:

1 var str = "Hello world!";
2 
3 console.log(str.split('').reverse().join(''));
4 //"!dlrow olleH"
5 console.log(str.split(' ').reverse().join(' '));
6 //"world! Hello"      

   這裡由于每個函數傳回值都是與其相對應的數組或字元串,可以直接在這個傳回值上進行操作,是以我們還用到了鍊式調用的技巧。

  ⑤ slice和splice

   這兩個方法的差別和使用非常重要,又由于它們名字之間隻差一個字母,缺少練習時我們很容易會将其混淆。

   slice方法可以類比String.prototype.substring。指定一個參數n,它将傳回一個新數組,這個數組中含有原數組下标從n到末尾的所有元素。指定兩個參數a和b時,它将傳回一個新數組,這個數組含有原數組下标從a到b的所有元素(不得不說,用中文來描述真的非常蹩腳):

1 var myArray = [1, 2, 3, 4, 5, 6, 7, 8];
2 
3 var aNewArray = myArray.slice(3);
4 var aNewNewArray = myArray.slice(3, 5);
5 
6 console.log(aNewArray);
7 //[4, 5, 6, 7, 8]
8 console.log(aNewNewArray);
9 //[4, 5]      

   當然了,這兩種操作都是含頭不含尾的。如果不指定參數地使用slice,它将傳回一個跟原數組一模一樣的數組,利用這一點,我們可以用一句代碼複制一個數組。

   splice是修改一個數組的“萬能方法”,要注意它将直接在原數組上動刀,傳回值是被删除的元素組成的數組:

1 var myArray = ['CapAmerica', 'IronMan', 'Hulk', 'Thor'];
 2 // param: 從第4個元素開始操作,删除0個元素,加入新元素'BlackWidow'
 3 myArray.splice(3, 0, 'BlackWidow');
 4 // 由于删除0個元素,它将傳回一個空數組
 5 
 6 console.log(myArray);
 7 // ['CapAmerica', 'IronMan', 'Hulk', 'Thor', 'BlackWidow']
 8 
 9 // param:從第二個元素開始,删除三個元素,加入這些新元素
10 myArray.splice(2, 3, 'ScarletWitch', 'Vision', 'CapMarvel');
11 //傳回['Hulk', 'Thor', 'BlackWidow']
12 
13 console.log(myArray);
14 //['CapAmerica', 'IronMan', 'ScarletWitch', 'Vision', 'CapMarvel']      

  ⑥ concat

   concat方法不會動原數組,而是傳回新數組。它傳回一個将原數組和所有你填入的參數都合并在一起的新數組,是以我們想到了可以用它搭配splice方法來實作一個JavaScript版本的快速排序:

1 function quickSort(arr) {
 2     if(arr.length <=1) return arr;
 3     var pivotIndex = Math.floor(arr.length / 2);
 4     var pivot = arr.splice(pivotIndex, 1)[0];
 5     var left = [], right = [];
 6     for(var i = 0; i < arr.length; i++) {
 7         if(arr[i] < pivot) left.push(arr[i]);
 8         else right.push(arr[i]);
 9     };
10     return quickSort(left).concat(pivot, quickSort(right));
11 }      

總結:① JavaScript中的Array對象隻是一個内建的對象,并不是傳統意義上的數組,它在記憶體中不是連續的空間,是以隻能周遊元素來進行查找修改,性能較差但靈活性非常好。

   ② Array.prototype中有非常多的方法,常用的有以上這些:indexOf、push、pop、unshift、shift、sort、reverse、join、slice、splice和concat。還有很多其他的方法,要善用這些方法隻能靠多練習,慢慢積累。

繼續閱讀