01【JS數據結構與算法】數組

寫在前面

幾乎所有所有的編程語言中都支持了數組,JavaScript也不例外。在很多的編程語言中數組是用來存放一系列同種類型的值的,但是在我們的JS中,它卻可以存放不同類型的值,而且它的長度還可以隨着我們添加的值動態增加,所以在JS裏面使用數組,會讓我們有一種如絲般順滑的感覺。

接下來的內容我們按如下圖所示展開給大家介紹。

創建和初始化數組

在JS中創建和初始化數組有如下幾種方式:

            //數組初始化、賦值方式
            let dataArray_01 = new Array(); //初始化一個空數組
            let dataArray_02 = new Array(5); //初始化一個長度爲5的數組,如果裏面有大於等於2個以上元素,就相當於給數組賦值
            let dataArray_03 = new Array('X北辰北', 'xbeichen.cn', 'Geov', 23); //創建一個含有四個元素的數組並賦值
            let dataArray_04 = []; //同dataArray_01
            let dataArray_05 = ['X北辰北', 'xbeichen.cn', 'Geov', 23]; //同dataArray_03

前三種方式我們使用JS內置的Array數組對象來實例化數組,後兩種方式直接通過簡寫方式來實例化數組,這兩種方式實例化出來的數組在用法上並沒有差別,實際開發中我們推薦使用後兩種中括號的方式去創建和初始化數組。

如果我們想獲取數組中的元素個數,或者說想獲取數組長度的話,可以直接使用length屬性去獲取,如下:

console.log(dataArray_01.length);

訪問數組元素和迭代數組

訪問數組中特定元素直接通過中括號加數組下標的方式訪問,下標從0開始計數。

數組迭代可以通過一層for循環來實現,如下:

            //訪問數組元素、迭代數組
            console.log(dataArray_05[1]); //輸出'xbeichen.cn'
            for (let i = 0; i < dataArray_05.length; i++) {
                //迭代數組中所有元素,並輸出
                console.log(dataArray_05[i]);
            }

在數組中添加元素和刪除元素

在數組中添加和刪除元素分爲以下三種情況;

  • 在數組頭部添加元素、刪除元素
  • 在數組尾部添加元素、刪除元素
  • 在數組中間某一位置添加元素、刪除元素

下面我們就以上三種情況,分別來介紹下該如何去操作。

1、在數組頭部添加元素、刪除元素

在數組的頭部位置添加元素的話,我們需要先將數組中每一項位置向後移動一位,騰出下標是0的位置,然後將要添加的元素添加到這個位置即可,代碼如下:

            //頭部添加元素
            let originData = [1, 2, 3, 4, 5];
            function preInsert(arr, value) {
                //遍歷數組中每一項
                for (let i = arr.length; i >= 0; i--) {
                    //將每一項元素位置後移一位,騰出arr[0]的位置
                    arr[i] = arr[i - 1];
                }
                arr[0] = value; //arr[0]位置插入新值
                return arr;
            }
            console.log(preInsert(originData, 88)); //輸出[88, 1, 2, 3, 4, 5]

除了上述直接上手自己實現之外,JS中的數組提供了一個方法,我們直接可以通過這方法來實現數組頭部位置的元素添加,如下:

            originData.unshift(99);
            console.log(originData); //輸出[99, 88, 1, 2, 3, 4, 5]

在數組頭部位置刪除元素的話,同理,我們只需要將數組中每一個元素往前移動一位即可,這樣一來,數組的第二項就覆蓋了原有的第一項元素,完成了數組頭部位置元素的刪除。但是這樣做完的話,我們數組的長度是沒有改變的,因爲最後一項是undefined,所以我們新定義一個數組,將刪除元素後的數組裏面不是undefined的元素賦值到新數組,然後將新數組返回即可,如下:

            //頭部刪除元素
            let originData = [1, 2, 3, 4, 5];
            function preRemove(arr) {
                let newArray = []; //定義一個新數組,用於存放刪除後數組中不是undefined的元素
                //遍歷原數組,將每一項向前移動一位,覆蓋前一位元素
                for (let i = 0; i < arr.length; i++) {
                    arr[i] = arr[i + 1];
                }
                //遍歷完成覆蓋後的數組,去除掉覆蓋後的數組中最後一項值爲undefined的元素
                for (let j = 0; j < arr.length; j++) {
                    if (arr[j] != undefined) {
                        newArray.push(arr[j]); //push方法用於向數組中尾部添加元素
                    }
                }
                return newArray;
            }
            console.log(preRemove(originData)); //輸出[2, 3, 4, 5]

同樣的,刪除數組中第一個元素,JS中的數組提供了一個方法,我們直接可以通過這方法來實現數組頭部位置的元素刪除,如下:

            originData.shift();
            console.log(originData); //輸出[3, 4, 5]

2、在數組尾部添加元素、刪除元素

在數組的尾部添加元素相比於在頭部位置添加元素的話顯得特別簡單,我們只需要在數組的最後位置增加一個空位,然後將值賦上去即可,這樣操作可行是因爲在JS中,數組是可以動態增長的,如下:

            //尾部增加元素
            let originData = [1, 2, 3, 4, 5];
            function laterInsert(arr, value) {
                //直接在數組最後位置添加空位並賦值即可,
                //因爲數組實際長度是arr.length-1,arr[arr.length]就相當於在數組最後位置增加了一個空位
                arr[arr.length] = value;
                return arr;
            }
            console.log(laterInsert(originData, 88)); //輸出[1, 2, 3, 4, 5, 88]

除了上述直接上手自己實現之外,JS中的數組提供了一個方法,我們直接可以通過這方法來實現數組尾部位置的元素添加,如下:

            originData.push(99);
            console.log(originData); //輸出[1, 2, 3, 4, 5, 88, 99]

在數組最後位置刪除元素,我們也不需要移動元素位置,只需要將原數組中的n-1(n是原數組長度)個元素賦值到一個新數組,然後返回這個新數組即可,如下:

            //尾部刪除元素
            let originData = [1, 2, 3, 4, 5];
            function laterRemove(arr) {
                let newArray = []; //定義一個新數組
                for (let i = 0; i < arr.length - 1; i++) {
                    //循環遍歷原數組的前n-1項,並將其每一項都賦值到新數組
                    newArray[i] = arr[i];
                }
                return newArray;
            }
            console.log(laterRemove(originData)); //輸出[1, 2, 3, 4]

同樣的,刪除數組中最後一個元素,JS中的數組提供了一個方法,我們直接可以通過這方法來實現數組尾部位置的元素刪除,如下:

            originData.pop();
            console.log(originData); //輸出[1, 2, 3]

3、在數組中間某一位置添加元素、刪除元素

在數組中間的某一位置要實現添加元素和刪除元素的話其實我們自己寫代碼也是可以實現的,只需要將上述代碼進行修改、增加判斷條件這些就可以做到,在這裏我們就不做詳細的介紹。我們如果想在數組中間某一位置添加元素和刪除元素的話,在這裏給大家介紹splice()這個方法,這個方法既可以實現任意位置添加元素,也可以實現任意位置元素的刪除,用法如下:

            //在中間某一位置刪除元素
            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9];
            //從索引是2的位置開始,刪除4個元素,即刪除originData[2]、originData[3]、originData[4]、originData[5]
            originData.splice(2, 4);
            console.log(originData); //輸出[1, 2, 7, 8, 9]
            //在中間某一位置添加元素
            let originData = [1, 2, 3, 4];
            //從索引是2的位置開始,刪除0個元素,然後在此位置添加從第三個參數開始依次往後的各個元素
            //即在索引是2的位置處依次插入77、88、99這三個元素
            originData.splice(2, 0, 77, 88, 99);
            console.log(originData); //輸出[1, 2, 77, 88, 99, 3, 4]

二維數組和多維數組

在JS中是不支持二維數組(矩陣)、多維數組這些的,它僅僅支持一維數組。但是我們可以通過數組套數組的方式來實現二維數組或者任一多維數組,代碼如下:

            //定義二維數組、迭代二維數組
            let arrayData2D = []; //定義二維數組
            arrayData2D[0] = [1, 2, 3, 4, 5];
            arrayData2D[1] = [6, 7, 8, 9, 10];
            console.table(arrayData2D);

            //迭代
            for (let i = 0; i < arrayData2D.length; i++) {
                for (let j = 0; j < arrayData2D[i].length; j++) {
                    console.log(arrayData2D[i][j]);
                }
            }

多維數組的話跟上述一樣,不過數組套數組部分我們直接通過for循環來做,如下:

            //定義三維數組、迭代三維數組
            let arrayData3D = [];
            for (let i = 0; i < 5; i++) {
                arrayData3D[i] = []; //初始化每一個緯度的數組
                for (let j = 0; j < 5; j++) {
                    arrayData3D[i][j] = []; //初始化每一個緯度的數組
                    for (let k = 0; k < 5; k++) {
                        arrayData3D[i][j][k] = i + j + k; //數組中的每一項存儲當前座標的數值之和
                    }
                }
            }
            console.table(arrayData3D);

            //迭代
            for (let i = 0; i < arrayData3D.length; i++) {
                for (let j = 0; j < arrayData3D[i].length; j++) {
                    for (let k = 0; k < arrayData3D[i][j].length; k++) {
                        console.log(arrayData3D[i][j][k]);
                    }
                }
            }

以上我們展示了一下三維數組的實例化和遍歷,其他四維數組、五維數組……這些高維數組,我們只需要依次增加for循環去做就可以了,不過實際開發中三維和四維數組已經用的不太多了,所以大家沒必要再去學習更高維的數組了。

JS數組方法

JS中的數組爲我們提供了很多的方法,供我們去操作數組,能熟練使用這些方法的話會對我們接下來實現其他數據結構帶來便利,我們來看看以下幾種核心方法:

下表詳述了數組的一些核心方法,其中的一些我們已經學習過了。


方 法         描 述

concat        連接 2 個或更多數組,並返回結果

every         對數組中的每個元素運行給定函數,如果該函數對每個元素都返回 true ,則返回 true

filter        對數組中的每個元素運行給定函數,返回該函數會返回 true 的元素組成的數組

forEach       對數組中的每個元素運行給定函數。這個方法沒有返回值

join          將所有的數組元素連接成一個字符串

indexOf       返回第一個與給定參數相等的數組元素的索引,沒有找到則返回 -1

lastIndexOf   返回在數組中搜索到的與給定參數相等的元素的索引裏最大的值

map           對數組中的每個元素運行給定函數,返回每次函數調用的結果組成的數組

reverse       顛倒數組中元素的順序,原先第一個元素現在變成最後一個,同樣原先的最後一個元素變成了現在的第一個

slice         傳入索引值,將數組裏對應索引範圍內的元素作爲新數組返回

some          對數組中的每個元素運行給定函數,如果任一元素返回 true ,則返回 true

sort          按照字母順序對數組排序,支持傳入指定排序方法的函數作爲參數

toString      將數組作爲字符串返回

valueOf       和 toString 類似,將數組作爲字符串返回


除了上述提出的方法之外,我們在文章開始的時候已經介紹過push()、pop()、shift()、unshift()、splice()這些方法,接下來我們再挑幾個上述列表中的方法給大家介紹一下。

1、數組合並

數組的合併如果我們想自己編碼實現的話很簡單,只需要迭代各個數組中的元素,然後將其最終賦值到我們的結果數組中就可以,但是JS的數組對象給我們提供了一個用於數組合並的方法concat(),用法如下:

            //數組合並
            let arrayData_01 = [1, 2, 3];
            let arrayData_02 = [8, 9];
            let resultData = arrayData_01.concat(88, 'testValue', arrayData_02);
            console.log(resultData); //輸出[1, 2, 3, 88, "testValue", 8, 9]

2、數組迭代——every

every()方法主要是用來檢測數組中的所有元素是否滿足某一條件,如果有一個元素不滿足條件就直接返回false,剩餘元素不再進行檢測。

every()方法不會改變原數組。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.every(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出false,因爲第一項就不滿足,後面剩餘元素不再檢測

3、數組迭代——some

some()方法主要用來檢測數組中是否有元素滿足某一條件,如果有滿足條件的元素直接返回true,剩餘元素不再進行檢測。

some()方法不會改變原數組。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.some(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出true,因爲第一項不滿足,但是第二項滿足條件,所以返回true,後面剩餘元素不再檢測

4、數組迭代——forEach

forEach()方法主要是遍歷數組中的每一項,並將其傳遞給回調函數,它跟for循環遍歷數組是一樣的。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.forEach(function (value) {
                console.log(value);
            });
            //依次輸出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

5、數組迭代——map和filter

map()方法也會迭代數組,但是它會返回一個新數組,這個新數組中的值是回調函數中每一次的執行結果。

map()方法不會改變原數組。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.map(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出[false, true, false, true, false, true, false, true, false, true]

filter()方法主要用來篩選數組,它也會返回一個新數組,但是新數組中的值是符合回調函數條件的值。

filter()方法不會改變原數組。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.filter(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出[2, 4, 6, 8, 10]

6、數組迭代——reduce

reduce()方法的回調函數接收四個參數,但是平時我們僅用前兩個,分別表示數組中的前一個元素和當前元素。reduce()方法的回調函數其實就是一個累加器,它會將數組中的值從左至右進行計算(縮減),最終數組中的所有值會計算得到一個結果,然後它將這個結果返回。所以reduce()方法非常適合求數組中所有元素的和。

reduce()方法不會改變原數組。

使用方法如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.reduce(function (preValue, laterValue) {
                return preValue + laterValue;
            });
            console.log(resultData); //輸出55

7、ES6和ES6+中新增的數組方法

除了以上的幾種方法之外,我們再來介紹幾種ES6和ES7中新增加的操作數組的方法。


方 法         描 述

@@iterator    返回一個包含數組鍵值對的迭代器對象,可以通過同步調用得到數組元素的鍵值對

copyWithin    複製數組中一系列元素到同一數組指定的起始位置

entries       返回包含數組所有鍵值對的 @@iterator

includes      如果數組中存在某個元素則返回 true ,否則返回 false 。E2016新增

find          根據回調函數給定的條件從數組中查找元素,如果找到則返回該元素

findIndex     根據回調函數給定的條件從數組中查找元素,如果找到則返回該元素在數組中的索引

fill          用靜態值填充數組

from          根據已有數組創建一個新數組

keys          返回包含數組所有索引的 @@iterator

of            根據傳入的參數創建一個新數組

values        返回包含數組中所有值的 @@iterator


下面我們還是來挑幾個常用的方法做一下介紹。

7.1、for……of循環迭代

JS中的數組循環除了for循環和forEach循環之外,在ES6中還提供了另一種循環方式,即for……of循環,下面來看下具體用法:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            for (const n of originData) {
                console.log(n);
            }
            //依次輸出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

7.2、@@iterator屬性

ES6在JS中的Array類中新增加了一個@@iterator屬性,這個屬性通過如下方法來使用:

            let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            console.log(iterator.next().value); //輸出1
            console.log(iterator.next().value); //輸出2
            console.log(iterator.next().value); //輸出3
            console.log(iterator.next().value); //輸出4
            console.log(iterator.next().value); //輸出5
            console.log(iterator.next().value); //輸出undefined
            console.log(iterator.next().value); //輸出undefined

上述方法在iterator.next().value迭代完之後,後面的數據值都是undefined。除了上述的迭代方法之外,還可以通過下面的方式迭代裏面的數據:

            let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            for (const i of iterator) {
                console.log(i);
            }
            //輸出1, 2, 3, 4, 5

7.3、entries、keys和values方法

entries()、keys()和values()三個方法都是ES6中新增的,爲了獲取數組中的迭代器,用法如下:

            let originData = [1, 2, 3, 4];
            let entriesValue = originData.entries();
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);

            let keysValue = originData.keys();
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());

            let valValue = originData.values();
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());

7.4、from方法

from()方法會根據一個已有數組返回一個新數組,此方法可以用來複制數組,也可以傳入第二個參數來篩選數組或計算數組,如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData_01 = Array.from(originData);
            console.log(resultData_01); //輸出[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

            let resultData_02 = Array.from(originData, function (value) {
                return value % 2 === 0 ? value : false;
            });
            console.log(resultData_02); //輸出[false, 2, false, 4, false, 6, false, 8, false, 10]

7.5、Array.of方法

Array.of()方法根據傳入的參數創建一個新數組。也可以用它來複制已有的數組,用法如下:

            let originData = Array.of(1, 2, 3);
            console.log(originData); //輸出[1, 2, 3]

            let resultData = Array.of(...originData);
            console.log(resultData); //輸出[1, 2, 3]

7.6、fill方法

fill()方法用於填充數據,支持全部填充,指定位置填充。用法如下:

            let originData = [1, 2, 3, 4, 5];
            originData.fill(88);
            console.log(originData); //輸出[88, 88, 88, 88, 88]

            originData.fill(99, 2);
            console.log(originData); //輸出[88, 88, 99, 99, 99]

            originData.fill(77, 1, 3);
            console.log(originData); //輸出[88, 77, 77, 99, 99]

7.7、copyWithin方法

copyWithin()方法主要是用來將數組中指定位置和個數的元素複製到原數組的指定位置,如下:

            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.copyWithin(0, 3);
            console.log(originData); //輸出[4, 5, 6, 7, 8, 9, 10, 8, 9, 10]
            originData.copyWithin(0, 3, 5);
            console.log(originData); //輸出[7, 8, 6, 7, 8, 9, 10, 8, 9, 10]

8、元素的排序

在介紹元素排序之前,先給大家介紹一個reverse()方法,這個方法會將我們數組中的元素反序輸出,使用方法如下:

            let originData = [1, 2, 3, 4, 5];
            console.log(originData.reverse()); //輸出[5, 4, 3, 2, 1]

除了上述可以將數組元素反序的方法之外,JS數組還向我們提供了一個供元素排序的方法,叫做sort()方法,在這個方法中通過傳入一個自定義函數,數組元素會按照我們指定的順序進行排序輸出,如下:

            let originData = [3, 1, 2, 5, 4];
            originData.sort(function (a, b) {
                //實現降序
                return b - a;
            });
            console.log(originData); //輸出[5, 4, 3, 2, 1]

9、元素搜索

JS的數組爲我們提供了indexOf()和lastIndexOf()兩個方法供我們在數組中查找元素,第一個方法返回與參數匹配的第一個元素的索引,第二個方法返回與參數匹配的最後一個元素的索引。除了這兩個方法之外,ES6和ES7中還增加了一些供數組查找的方法。

ES6新增find()和findIndex()方法。

ES7新增includes()方法。

以上各種方法的使用,如下:

            //元素搜索
            let originData = [1, 2, 3, 4, 3, 3, 4];

            console.log(originData.indexOf(3)); //輸出2
            console.log(originData.lastIndexOf(3)); //輸出5

            let findValue = originData.find(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findValue); //輸出2
            let findIndexValue = originData.findIndex(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findIndexValue); //輸出1

            console.log(originData.includes(4)); //輸出true

10、將元素輸出爲字符串

JS的數組中還提供了兩個方法,可以將數組中的元素輸出爲字符串,使用方法如下:

            //元素輸出爲字符串
            let originData = [1, 2, 3, 4, 5];
            console.log(originData.toString()); //輸出1,2,3,4,5
            console.log(originData.join('-')); //輸出1-2-3-4-5

JS類型數組

我們以上介紹的數組裏面是可以存儲任意類型數據的,所以JS裏的數組不是強類型的,但是我們可以用以下的方式聲明和定義一個強類型的數組,這就是類型數組。


類型數組              數據類型

Int8Array             8 位二進制補碼整數

Uint8Array            8 位無符號整數

Uint8ClampedArray     8 位無符號整數

Int16Array            16位二進制補碼整數

Uint16Array           16位無符號整數

Int32Array            32位二進制補碼整數

Uint32Array           32位無符號整數

Float32Array          32 位 IEEE 浮點數

Float64Array          64 位 IEEE 浮點數


以上就是類型數組支持的數據類型,我們簡單來看下具體使用:

            //類型數組
            let typeArray = new Int32Array(5); //定義一個長度爲5的整數數組
            typeArray[0] = 32.5; //賦值一個浮點數
            typeArray[1] = 22;
            console.log(typeArray); //輸出[32, 22, 0, 0, 0]

總結

本篇文章中我們簡單介紹了一下數組,包括數組的定義、具體的操作、二維數組和多維數組以及數組的元素增加和刪除等。在JS中的數組其實和其他語言中的數組是不一樣的,所以我們在介紹其他數據結構之前先給大家介紹一下數組這個數據結構,後面的其他數據結構都是在數組基礎之上的,所以大家看完這篇文章後就可以接下來學習其他的數據結構了。我們下一篇給大家介紹一下JS中的另一個數據結構——棧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章