iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 10
0
Modern Web

JavaScript Note系列 第 10

Array 陣列

陣列就像容器一樣,放在裡面的東西稱為元素,會按照順序排好,每個元素都有其位置,稱為索引,找到索引值,就可以得知該位置元素的值。

建立陣列最直接的方式是使用中括號:

let ary1 = []; //建立一個空陣列,裡面沒有任何元素
let ary2 = [1,2,3]; //有3個元素的陣列,元素型別為number
let ary3 = [1,'a',true]; //不同型別的元素
let ary4 = [ [1,2,3],[4,5,6] ]; //陣列中也可以包含陣列
let ary5 = [ {x:1,y:2},{x:3,y:4} ]; //陣列中也可以包含物件

存取陣列

存取陣列中指定位置的值,必須使用索引值才能找到位置,並存取。
陣列的索引值是number型別,起始值是0。

let a = []; //空陣列
a[0] = 1; //設定a陣列的索引值0,也就是第1個元素值為1
a[1] = 2; //設定a陣列的索引值1,也就是第2個元素值為2

陣列也是物件

假設我們要存取o物件中的x屬性,會使用o.x或o['x'],同樣地,a[0]中,首先會將索引0轉為字串'0',表示a陣列(物件)的'0'屬性的值為1。
陣列的屬性名稱同時也是物件的屬性名稱,但只有在陣列的屬性名稱是介於0~https://chart.googleapis.com/chart?cht=tx&chl=2%5E%7B32%7D -1(含)之間的整數時,此時屬性才會被視為索引,同時也會影響該陣列另一個屬性length的值。
當我們要存取物件不存在的屬性時,不會發生錯誤,而是會回傳undefined。
陣列也是如此,不存在的索引或屬性名稱也是會得到undefined。

判斷陣列

我們可以使用Array.isArray( )函式來判斷,該物件是否為陣列。

let ary = [1, 2, 3, 4, 5, 6];
let obj = {
    x: 2,
    y: 6
};
console.log(Array.isArray(ary)); //true
console.log(Array.isArray(obj)); //false

字串

字串在JS中的行為類似陣列,每個元素都可視為字元,所以能用[ ]中括號,讀取值。

let str = 'Hello';
console.log(str[1]); //e

即便它的行為很像陣列,但實際型別依舊是string,而不是陣列。

let str = 'Hello';
console.log(str[1]); //e
console.log(typeof str); //string
console.log(Array.isArray(str)); //false

陣列方法

indexOf(searchElement,fromIndex)

搜尋陣列中是否有符合給定值的元素,若有,就回傳第一個符合元素的索引值;若無,回傳-1。
searchElement:
指定要搜尋的值。
fromIndex:
指定起始索引值,若無給值,預設從第一個元素開始搜尋。

let ary = ['A', 'B', 'C', 'D', 'E', 'F'];
console.log(ary.indexOf('D')); //3
console.log(ary.indexOf('X')); //-1
console.log(ary.indexOf('D', 2)); //3
console.log(ary.indexOf('B', 2)); //-1

join( )

join( )方法可以將陣列中的所有元素轉成字串,並串接成一個字串,再回傳結果,若沒指定分隔符號,預設是逗號。

let ary = ['A', 'B', 'C', 'D'];
console.log(ary.join()); //A,B,C,D
console.log(ary.join('')); //ABCD
console.log(ary.join('-')); //A-B-C-D

reverse( )

將陣列中元素的排列順序倒轉過來,會改變原陣列。

let ary = ['A', 'B', 'C', 'D'];
console.log(ary.reverse()); //["D", "C", "B", "A"]
console.log(ary); //["D", "C", "B", "A"]

sort( )

排序陣列中的元素,會先將元素轉字串,再依據字串的Unicode編碼進行排序,會改變原陣列。

let ary = ['Sun', 'Mon', 'Tue', 'Wed'];
console.log(ary.sort()); //["Mon", "Sun", "Tue", "Wed"]
console.log(ary); //["Mon", "Sun", "Tue", "Wed"]

但如果我們想要以數值的大小作排序,因為它比較的是字串,所以產生的結果不是預期的。

let nums = [10, 9, 50, 35];
console.log(nums.sort()); //[10, 35, 50, 9]

這時可以使用一個比較的函式做為引數,來判斷元素的大小與排列順序。
採用匿名函式,包括2個參數。如果a-b<0,那a會排在b的前面,如果a-b>0,那a會排在b的後面,如果a-b=0,排序不變。

let nums = [10, 9, 50, 35];
console.log(nums.sort(function (a, b) {
    return a - b;
})); //[10, 35, 50, 9]

sort( )預設是將大寫排在前面。

let ary = ['Sun', 'mon', 'tue', 'Wed'];
console.log(ary.sort()); //["Sun", "Wed", "mon", "tue"]

如果想不區分大小寫排序,可藉由toLowerCase( )方法來達成。

concat( )

將2個以上的陣列或進行陣列與字串合併成新的陣列。
合併2個:

let ary1 = ['a', 'b', 'c'];
let ary2 = ['d', 'e', 'f'];
console.log(ary1.concat(ary2)); //["a", "b", "c", "d", "e", "f"]

合併3個:

let ary1 = ['a', 'b', 'c'];
let ary2 = ['d', 'e', 'f'];
let ary3 = ['g', 'h', 'i'];
console.log(ary1.concat(ary2, ary3)); //["a", "b", "c", "d", "e", "f", "g", "h", "i"]

合併字面值與陣列:

let ary1 = ['a', 'b', 'c'];
let ary2 = ['d', 'e', 'f'];
let ary3 = ['g', 'h', 'i'];
console.log(ary1.concat(ary2, ary3, 'j', 'k', 1, 2));
//["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", 1, 2]

slice(start,end)

提取指定範圍的元素,回傳一個新陣列。
start:
起始索引值,如果為0,表示從第一個元素開始,-1表示從倒數第一個元素開始。
end:
結束索引值,擷取至該索引值之前的元素,3表示擷取至索引2為止,-3表示擷取至索引-4為止,如為空白,表示從start擷取至該陣列最後一個元素為止。

let ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.slice(1)); //["b", "c", "d", "e", "f"]
console.log(ary.slice(2, 5)); //["c", "d", "e"]
console.log(ary.slice(2, -1)); //["c", "d", "e"]
console.log(ary.slice(-3)); //["d", "e", "f"]
console.log(ary.slice(-4, 4)); //["c", "d"]
console.log(ary.slice(-5, -2)); //["b", "c", "d"]

splice(start, deleteCount,value)

從索引start開始,刪除deleteCount個元素並插入value,會改變原陣列。
start:
起始索引值,如果為0,表示從第一個元素開始,-1表示從倒數第一個元素開始。
deleteCount:
欲刪除元素的數量,若空白,則會刪除到最後一個元素為止;若為0或負數,則不會刪除任何元素。
value:
欲加入陣列的值,若空白,則不會加入任何元素。
回傳值:
被刪除的元素陣列。

let ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(4)); // ["e", "f"]
console.log(ary); //["a", "b", "c", "d"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(3, 2)); //["d", "e"]
console.log(ary); // ["a", "b", "c", "f"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(3, 0)); //[]
console.log(ary); //["a", "b", "c", "d", "e", "f"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(-4, 2)); //["c", "d"]
console.log(ary); //["a", "b", "e", "f"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(-4, -2)); //[]
console.log(ary); //["a", "b", "c", "d", "e", "f"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(3, 0, 'A')); //[]
console.log(ary); //["a", "b", "c", "A", "d", "e", "f"]
ary = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(ary.splice(3, 1, 'A')); //["d"]
console.log(ary); //["a", "b", "c", "A", "e", "f"]

unshift( )

新增元素至陣列的開頭,並回傳陣列的新長度。

let a = [];
console.log(a.unshift('a')); //1
console.log(a.unshift('b')); //2
console.log(a.unshift('c', 'd')); //4
console.log(a); //["c", "d", "b", "a"]

需要注意,如果一次新增2個(以上)的元素,它會一次把所有元素插入,並維持原本在引數中的順序。

toString( )

陣列也是物件,所以它也有toString()方法。

let ary = ['a', 'b', 'c'];
console.log(ary.toString()); //a,b,c

它會將元素轉成字串,並以逗號區隔成字串回傳。

forEach(value,index,array)

會逐次地將元素傳入callbackfn,每傳遞一次,callbackfn就執行一次。
會改變原陣列。
value
元素值
index
索引值
array
傳入的陣列本身

let ary = [1, 2, 3, 4, 5, 6];
let sum = 0;
ary.forEach(function (v) {
    sum += v;
})
console.log(sum); //21
ary.forEach(function (v, i, a) {
    a[i] = v + 1;
})
console.log(ary); //[2, 3, 4, 5, 6, 7]

如果只傳入單一引數,就代表元素的值。

map( )

會逐次地將元素傳入callbackfn,每傳遞一次,callbackfn就執行一次。
回傳一個由callbackfn運算後,所組成的陣列。

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.map(function (x) {
    return x * x;
})); //[1, 4, 9, 16, 25, 36]

map( )對callbackfn的呼叫方式跟forEach一樣,差別在於map( )會回傳新陣列,不會修改原陣列。

filter( )

將元素依序傳入callbackfn中運算,運算結果為boolean值,回傳運算結果為true的元素所組成的陣列。

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.filter(function (x) {
    return x < 4;
})); // [1, 2, 3]

實作搜尋篩選

let weeks = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];

function filterWeeks(query) {
    return weeks.filter(function (el) {
        return el.toLowerCase().indexOf(query.toLowerCase()) > -1;
    })
}
console.log(filterWeeks('ur')); //["thursday", "saturday"]
console.log(filterWeeks('nd')); //["sunday", "monday"]

將el的值轉成小寫,再使用String的indexOf方法確認是否有包括query的值,若有回傳索引值會大於-1,比較結果為true,filter( )會將該元素放入回傳的陣列中;若無,indexOf( )回傳-1,比較結果為false,filter( )就不會取出該元素。

every( )

callbackfn會對陣列中的每個元素條件運算,只有全部的元素都為true,every( )才會回傳true,不然則回傳false。

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.every(function (x) {
    return x < 4;
})); //fasle
console.log(ary.every(function (x) {
    return x > 0;
})); //true

every( )會在第一次遇到運算結果為false時,就停止繼續對元素運算:

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.every(function (x) {
    console.log(x);
    return x < 4;
}));

https://ithelp.ithome.com.tw/upload/images/20181024/201125733lj0BAGXgu.png

some( )

callbackfn會對陣列中的每個元素條件運算,只要有一個(以上)元素為true,some( )就會回傳true,不然則回傳false。

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.some(function (x) {
    return x < 4;
})); //true

some( )會在第一次遇到運算結果為true時,就停止繼續對元素運算:

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.some(function (x) {
    console.log(x);
    return x < 4;
}));

https://ithelp.ithome.com.tw/upload/images/20181024/20112573dxXwQkylgw.png

reduce(callbackfn(accumulator, currentValue){}, initialValue)

會逐次地將元素傳入callbackfn,最終結果會產生一個值,並回傳。

let ary = [1, 2, 3, 4, 5, 6];
console.log(ary.reduce(function (x, y) {
    return x + y;
}, 0)); //21

它的運作方式如下:
callbackfn第一次執行時,若有initialValue,則accumulator會等於initialValue,currentValue會等於陣列的第一個元素值。若無initialValue,則accumulator會等於陣列的第一個元素值,currentValue會等於陣列的第二個元素值。
以上面的例子來說,第一次執行時,x=0,y=1,回傳值為0+1=1。
第二次執行callbackfn,accumulator會是上一次執行的回傳值,也就是1,currentValue是上次傳入做為引數的元素的下一個,也就是第二個元素,值為2。
依此類推,第三次x=3,y=3,直到最後一個元素為止,reduce( )會回傳最終運算值:21。

參考來源:
MDN Array
JavaScript大全
Speaking JavaScript|簡明完整的 JS 精要指南
新一代 JavaScript 程式設計精解


上一篇
undefined & null
下一篇
堆疊(Stack) & 佇列(Queue)
系列文
JavaScript Note31

尚未有邦友留言

立即登入留言