JavaScript陣列的使用小結(詳細還是去看MDN)

六奇發表於2019-03-19

JavaScript中的陣列是一種特殊的物件,由於物件的屬性必須是字串的形式,所以陣列的數字索引在內部被轉為字串型別。

建立陣列

1.0 直接用 []建立

陣列中的元素可以是不同的資料型別

var arr1 = [1,2,3,4,"hello","adf",false]; // 陣列中的元素可以是不同的資料型別
console.log(arr1) //[ 1, 2, 3, 4, 'hello', 'adf', false ]
複製程式碼

2.0 用Array物件建立

var arr2 = new Array(1,2,4,5,"abc",true)
console.log(arr2) //[ 1, 2, 4, 5, 'abc', true ]
複製程式碼

Array建構函式有一個很大的缺陷,就是不同的引數,會導致它的行為不一致。

// 無引數時,返回一個空陣列
new Array() // []

// 單個正整數引數,表示返回的新陣列的長度
new Array(1) // [ empty ]
new Array(2) // [ empty x 2 ]

// 非正整數的數值作為引數,會報錯
new Array(3.2) // RangeError: Invalid array length
new Array(-3) // RangeError: Invalid array length

// 單個非數值(比如字串、布林值、物件等)作為引數,
// 則該引數是返回的新陣列的成員
new Array('abc') // ['abc']
new Array([1]) // [Array[1]]

// 多引數時,所有引數都是返回的新陣列的成員
new Array(1, 2) // [1, 2]
new Array('a', 'b', 'c') // ['a', 'b', 'c']
複製程式碼

3.0 通過字串的split()方法生成陣列

var s = "i am a web coder i can say hello world!";
var arr3 = s.split(" "); // split()函式的引數是指定分隔符,然後通過分隔符分割字串形成陣列
console.log(arr3) //[ 'i', 'am', 'a', 'web', 'coder', 'i', 'can', 'say', 'hello', 'world!' ]
複製程式碼

4.0 用已有的陣列建立陣列

4.0.1 通過陣列拼接

concat拼接陣列是生成了一個新的陣列,原陣列不發生變化

var a1 = [1,2,3];
var a2 = [4,5,6];
var a3 = a1.concat(a2); // 將a2中的元素按順序拼接到a1的元素後面並生成兩者拼接的新陣列
console.log(a1); //[ 1, 2, 3 ] a1沒有發生變化
console.log(a2); //[ 4, 5, 6 ] a2沒有發生變化
console.log(a3); //[ 1, 2, 3, 4, 5, 6 ] a1和a2的順序拼接
複製程式碼

4.0.2 通過陣列擷取

splice擷取陣列,原陣列會發生變化,可用來刪除陣列中的元素

var b1 = [1,2,3,4,5];
var b2 = b1.splice(3,3); // 將b1陣列中的從索引3開始擷取最多3個元素,然後將擷取的子陣列賦值給b2
console.log(b1); // [ 1, 2, 3 ] b1陣列會發生改變,截去splice的部分
console.log(b2); // [ 4, 5 ] b2陣列獲取splice(3,3)擷取的子陣列
複製程式碼

5.0 ES6 建立陣列的兩個API

5.0.1 Array.of

返回由所有引數值組成的陣列,如果沒有引數,就返回一個空陣列

var a = Array.of(1,2,3,4,5) // [1,2,3,4,5]
var b = Array.of(7) // [7]
複製程式碼

5.0.2 Array.from

定義:用於將兩類物件轉為真正的陣列(不改變原物件,返回新的陣列)。
引數:
第一個引數(必需):要轉化為真正陣列的物件。
第二個引數(可選): 類似陣列的map方法,對每個元素進行處理,將處理後的值放入返回的陣列。
第三個引數(可選): 用來繫結this。

// 類陣列是索引是 0 1 2 3... 並且有length屬性的物件
let obj = {0: 'a', 1: 'b', 2:'c', length: 3};
let arr = Array.from(obj); // ['a','b','c'];
複製程式碼

增加陣列元素

1.0 直接通過下標新增

通過陣列索引新增,若新增的索引位置原來有值則更新原來的值,若沒有值則新建一個陣列元素,若新建的元素與之前的陣列元素不連續,則中間的資料位置保留併為undefined

var a = [1,2,3];
a[a.length] = 4; //在末尾增加一個元素
console.log(a); // [ 1, 2, 3, 4 ]
a[10] = 10; //索引超過 a.length 也是可以插入的,陣列會保留前面沒有資料的位置
console.log(a); //[ 1, 2, 3, 4, <6 empty items>, 10 ]
console.log(a[8]); // undefined 保留的資料位置會設定為 undefined
複製程式碼

2.0 通過push在尾部新增

push可以在陣列的末尾新增1個或者多個元素,並返回新增完畢之後陣列中元素的個數

var b = [1,2,3];
var b_length = b.push(4);
console.log(b_length); // 4 push的返回值是新增完元素之後的陣列長度
b.push(5,6); //可以一次插入一個或者多個
console.log(b); // [ 1, 2, 3, 4, 5, 6 ]
複製程式碼

3.0 通過unshift在陣列頭部插入

unshift可以在陣列的頭部插入一個或者多個元素,並返回新增完畢之後陣列中的元素個數

var c = [1,2,3];
var c_length = c.unshift(4);
console.log(c_length); // 4 unshift返回的值是新增玩元素之後的陣列長度
c.unshift(5,6);
console.log(c); //[ 5, 6, 4, 1, 2, 3 ]
複製程式碼

4.0 通過splice自由的插入元素

splice有3個元素, 第一個是索引,刪除或者新增的位置, 第二個是刪除的元素個數,第三個是新增的元素

splice有多個元素, 第一個固定為索引,刪除或者新增的位置。第二個是刪除的元素個數,是 0 或者負數,則不移除元素。這種情況下,至少應新增一個新元素。第三個之後則是新增進陣列的元素

var d = ['a','b','c']
d.splice(3,0,4); // splice有3個元素, 第一個是索引,刪除或者新增的位置, 第二個是刪除的元素個數,第三個是新增的元素
console.log(d); // [ 'a', 'b', 'c', 4 ]
複製程式碼

刪除陣列元素

1.0 通過 pop 移除末尾的元素

pop移除陣列最後一個元素並將其返回

var a = [1,2,3];
var tmp = a.pop(); // 返回值為刪除的元素
console.log(tmp); // 3
console.log(a); // [1,2]
複製程式碼

2.0 通過shift 移除頭部的元素

shift移除陣列第一個元素並將其返回

var b = [1,2,3]; 
var tmp = b.shift(); // 返回值為刪除的元素
console.log(tmp); // 1
console.log(b); // [2,3]
複製程式碼

3.0 通過splice 刪除任意位置的元素

splice有3個元素, 第一個是索引,刪除或者新增的位置, 第二個是刪除的元素個數,第三個是新增的元素
在刪除陣列元素的時候一般只用前兩個,指定刪除的索引起始位置和刪除的個數,並將刪除的元素按照子陣列返回

var c = [1,2,3,4,5,6];
var tmp = c.splice(3,3); // 從索引3開始刪除最多3個元素,擷取的元素按照陣列的形式返回
console.log(tmp); //[4,5,6]
console.log(c); // [1,2,3]
複製程式碼

查詢陣列元素

1.0 通過indexOf查詢

indexOf查詢是否包含指定的元素,若存在則返回索引,不存在返回-1

var a = ['a','b','c','d'];
var index1 = a.indexOf('a');
var index2 = a.indexOf('e');
console.log(index1); //0
console.log(index2); //-1
複製程式碼

2.0 通過includes查詢

查詢陣列中是否含有某個元素,存在返回true,不存在返回false

var index3 = a.includes("a");  // 存在返回true 不存在返回false
console.log(index3);
複製程式碼

陣列排序

使用sort函式

對於字元型別的陣列,可以直接用**sort()**函式按照Unicode碼升序排序,如果需要反序使用reverse()

var a = ['abc','hello','qwen','bob']; // 預設按照Unicode碼的順序排序
a.sort();
console.log(a); // [ 'abc', 'bob', 'hello', 'qwen' ]
console.log(a.reverse()); //[ 'qwen', 'hello', 'bob', 'abc' ]
var b = [1,100,12,3,4];
b.sort();
// sort()方法排序的時候預設排序的物件是字串
// 所以在純數字排序的時候會將number型別轉成字串型別進行排序
console.log(b); //[ 1, 100, 12, 3, 4 ]


// 數字排序的方法 通過給sort()傳入一個比較函式

function compare(num2,num1){
    /**
     * 升序排序
     * 返回值大於0 表示交換位置
     * 返回值小於0 表示不用交換
     * 等於0 相等
     */
    return num2 - num1;
}
b.sort(compare)
console.log(b) // [ 1, 3, 4, 12, 100 ]
複製程式碼

陣列的進階操作

1.0 join

使用join()拼接陣列生成字串,並返回這個字串。其中join可以接受一個符號用來拼接字串,預設的情況下為直接串聯不新增任何拼接字串。

var arr = [1,'a',true,'hello'];
var string1 = arr.join('-');
var string2 = arr.join();
console.log(string1) // 1-a-true-hello
console.log(string2); // 1atruehello
複製程式碼

2.0 slice

slice(start,end)獲取原陣列的部分作為子陣列返回,原陣列不發生改變。擷取的時候遵循左閉右開原則。

var a = [1,2,3,4,5,6,7];
var b = a.slice(0,5); // 包含start,不包含end 左閉右開
console.log(a); // [ 1, 2, 3, 4, 5, 6, 7 ] 原陣列不發生改變
console.log(b); // [ 1, 2, 3, 4, 5 ]
複製程式碼

3.0 map

map()建立一個新陣列並返回,其中新陣列的每個元素由呼叫原始陣列中的每一個元素執行提供的函式得到,原陣列不發生改變

var a = [1,2,3,4,5,6];

function twoSize(item){
    return item * 2; //放大兩倍
}
var b = a.map(twoSize);
console.log(a); // [ 1, 2, 3, 4, 5, 6 ]
console.log(b); // [ 2, 4, 6, 8, 10, 12 ]

// 使用匿名函式

var c = a.map(function(item){
    return item * 3; // 放大三倍
});

console.log(c); //[ 3, 6, 9, 12, 15, 18 ]
複製程式碼

4.0 every

對陣列中的每個元素都執行一次指定的回撥函式,直到回撥函式返回false,此時every()返回false並不再繼續執行。如果回撥函式對每個函式都返回trueevery()函式也返回true

var a = [2,4,6,8,10];
var res1 = a.every(function(item){
    return item % 2 == 0;//判斷是否偶數
});
console.log(res1); //true

var res2 = a.every(function(item){
    return item % 2 != 0; //判斷是奇數
});// 在判斷第一個元素是否奇數的時候就返回了false,後面的不再執行
console.log(res2); //false
複製程式碼

可以將every(func)函式看成判斷陣列中的元素是否都滿足func指定的規則,若全部滿足返回true,若有一個不滿足則不再判斷返回false
操作類似於下面的截斷運算

var tmp3 = func(a[0])&&func(a[1])&&...&&func(a[n])
複製程式碼

5.0 some

對陣列中的每個元素都執行一次指定的回撥函式,直到回撥函式返回true,此時some()返回true並不再繼續執行。如果回撥函式對每個元素都返回false,那麼some()將返回false

var a = [1,2,3,4,5];
var res1 = a.some(function(item){
    return item % 2 == 0;//只要有一個為偶數就返回true
});

console.log(res1); //true
複製程式碼

可以將some(func)函式看成判斷陣列中的元素是否存在滿足func指定的規則的元素,若存在滿足的元素返回true,並不再向後判斷,若全部不滿足則返回false
操作類似於

var tmp3 = func(a[0]) || func(a[1]) ||...|| func(a[n])
複製程式碼

6.0 filter

建立一個新的陣列,包含通過所有提供函式實現的測試的所有元素。過濾陣列。原陣列不發生改變

var a = [1,2,3,4,5,6]
/*
item:當前的遍歷值
index:當前的索引
self:陣列物件
*/
var res = a.filter(function(item,index,self){
    return item % 2 == 0;//返回所有偶數
});

console.log(res); // [ 2, 4, 6 ]
複製程式碼

過濾陣列,返回符合回撥函式為true的元素

7.0 forEach

針對每一個元素執行提供的函式。會修改原來的陣列,不會返回執行結果,返回undefined

var a = [1,2,3,4,5];
a.forEach(function(item, index){
    // return item * 2; //無法直接擴大擴大兩倍
    a[index] = item * 2;
});
複製程式碼

8.0 reduce

Array的reduce()把一個函式作用在這個Array[x1, x2, x3...]上,這個函式必須接收兩個引數,reduce()把結果繼續和序列的下一個元素做累積計算,其效果就是:

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
複製程式碼

案例1:求累加和

var a = [1,2,3,4,5];
function add(total,next){
    return total + next; // 每次的返回值會作為下次呼叫add的total
}
var b = a.reduce(add);
console.log(b); // 15
複製程式碼

案例2:求元素出現的次數

var words = ["apple","hello","orange","apple"];

var wordCount = function(prev,next){
    prev[next] = (prev[next] + 1) || 1; // 如果存在就加1,否則設定為1
    return prev;
}

var obj = words.reduce(wordCount,{});
console.log(obj); // { apple: 2, hello: 1, orange: 1 }
複製程式碼

對reduce的思考:
reduce(callback,initiaValue)會傳入兩個變數,回撥函式(callback)和初始值(initiaValue)。如果不設定初始值,則第一次執行的時候,callback的第一個引數是陣列的第一個元素,第二個引數是陣列的第二個元素。有初始值則prev為初始值,next為陣列第一個元素。

陣列遍歷

1.0 length + for 迴圈

for(let i =0;i<arr.length;i++){
    console.log(i+":"+arr[i]);
}
複製程式碼

2.0 使用forEach

forEach中的回撥函式的兩個引數中值在前,索引在後

arr.forEach(function(val,index){
    console.log(index+":"+val);
});
複製程式碼

3.0 for ... in

for...in的方式遍歷的是陣列中的索引,前面也提到過陣列是一種特殊的物件,在預設的情況下是以0...n的數字作為索引,但是也可以用其他字元作為索引,所以當陣列中存在其他索引的時候可以用for...in獲取

for(let index in arr){
    console.log(index+":"+arr[index]);
}
複製程式碼

前面三種遍歷列印的值

/*
    0:a
    1:b
    2:c
    3:d
*/
複製程式碼

4.0 for ... of

for ... of直接遍歷陣列中的值

for(let val of arr){
    console.log(val);
}
/*
    a
    b
    c
    d
*/
複製程式碼

5.0 for...in 和 for...of的區別

for … in迴圈,它遍歷的實際上是物件的屬性名稱。
一個Array陣列實際上也是一個物件,它的每個元素的索引被視為一個屬性。
當我們手動給Array物件新增了額外的屬性後,for … in迴圈將帶來意想不到的意外效果:

var arr = ['a','b','c'];
arr.k = "hello";

for(let i in arr){
    console.log(i+":"+arr[i]); //遍歷的是屬性值
}
/*
    0:a
    1:b
    2:c
    k:hello
 */
console.log(arr); // [ 'a', 'b', 'c', k: 'hello' ]
複製程式碼

for ... of執行的時候,只遍歷值但是沒有去遍歷新加的k

var arr = ['a','b','c'];
arr.k = "hello";

for(let val of arr){
    console.log(val);
}
/*
    a
    b
    c
*/
複製程式碼

詳細看:developer.mozilla.org/zh-CN/docs/…

兩個升序陣列合為一個升序陣列

var arr1 = [1,6,7,8,9]
var arr2 = [2,3,4,5]

// 1.0 合併成一個陣列然後排序
function compare(num1,num2){
    return num1 - num2;
}
var res = arr1.concat(arr2)
res.sort(compare);
console.log(res); //[ 1, 2, 3, 4, 5, 6, 7, 8, 9]


// 2.0 用兩個指標 i j 指向兩個陣列的頭部依次比較插入

var i = 0;
var j = 0;
tmp = [];
while(i<arr1.length&&j<arr2.length){
    if(arr1[i]<=arr2[j]){
        tmp.push(arr1[i]);
        i++;
    }else{
        tmp.push(arr2[j]);
        j++;
    }
}
var res = tmp.concat(arr1.slice(i)).concat(arr2.slice(j)); //拼接沒有遍歷完的陣列
console.log(res)
複製程式碼

陣列去重

// 1.0 用set去重 然後用 Array.from轉為list
var myset = Array.from(new Set(arr));
console.log(myset); // [ 1, 2, 3, 4 ]

// 2.0 用reduce
function compare(num1,num2){
    return num1 - num2;
}
arr.sort(compare);//先排序
var res = arr.reduce(function(init,current){
    if(init.length===0||init[init.length-1]!=current){
        init.push(current);
    }
    return init;
},[]);
console.log(res); // [ 1, 2, 3, 4 ]

// 3.0 filter

var res = arr.filter(function(item,index,self){
    return self.indexOf(item) === index; //從前往後查詢對應元素的索引是否與當前索引相等,要是不相等說明之前出現過重複的元素
});
console.log(res);
複製程式碼

求兩個陣列的交集

遍歷其中一個陣列,然後用indexOf來判斷是否在另一個陣列中出現

var a = [1,2,3,4,4,5];
var b = [3,4,5,6,7];


// 1.0 用 indexOf
var res = []
for(let val of a){
    if(b.indexOf(val)!=-1){
        res.push(val);
    }
}
console.log(res); // [ 3, 4, 4, 5 ]
複製程式碼

求只出現一次的數字

一個非空陣列,其中只有一個元素只出現了一次,其餘均出現兩次,找出那個只出現一次的數字

// 1.0 用reduce
// 用 reduce統計出現次數
var res = a.reduce(function(init,current){
    init[current] = (init[current] + 1) || 1;
    return init;
},{});
// 遍歷結果選出出現一次的元素
for(let i in res){
    if(res[i]==1){
        console.log(i);// 3
    }
}
複製程式碼

兩數之和

給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。需要考慮的是4-2=2這時候陣列中必須有兩個2
暴力方法

var arr = [1,2,3,5,9];
var target = 7;
// 暴力遍歷 假設只有一組數相加為

for(let i=0;i<arr.length;i++){
    for(let j=i+1;j<arr.length;j++){
        if(arr[i]+arr[j]==target){
            console.log(arr[i],arr[j])
        }
    }
}
複製程式碼

使用map

var arr = [1,2,5,2,9];
var target = 4;
// 使用map
var m = new Map();
var res = []; // 存放索引
for(let i=0; i<arr.length ;i++){
    if(m.has(target-arr[i])){
      // 第一次遇到就往裡面存,這裡若存在一定是之前存入的,不會與這次起衝突
        res.push(i,m.get(target-arr[i])); 
        break;
    }
    m.set(arr[i],i);
}
console.log(res);
複製程式碼

判斷陣列中的元素是否唯一

使用set ,然後比較轉為set之後的大小和原來的大小

var a = [1,2,3,4]
var b = [1,2,1,3];

function judge(arr){
    let s = new Set(arr);
    if(s.size==arr.length){
        return true;
    }
    return false;
}
var flag1 = judge(a);
var flag2 = judge(b);

console.log(flag1); //true
console.log(flag2); //false
複製程式碼

移動零

將陣列中所有元素值為0的元素移動到陣列的末尾
1)必須在原陣列上操作,不能拷貝額外的陣列
2)儘量減少操作次數

用一個新索引記錄不是0的數,並新增到原陣列中,之後補全沒有新增進去的0

var arr = [1,0,0,2,0,3,4,5];
var index = 0; //陣列新的索引
const num = 0;//比較的物件

for(let i=0;i<arr.length;i++){
    if(arr[i]!=num){
        // 不為零就用新索引新增到原陣列中
        arr[index] = arr[i];
        index += 1;
    }
}
for(let i=index;i<arr.length;i++){
    arr[i] = num;//補上之前沒有新增的0
}
console.log(arr); //[ 1, 2, 3, 4, 5, 0, 0, 0 ]
複製程式碼

JavaScript中的坑點

這裡有一個問題需要特別注意,如果字串鍵值能夠被強制型別轉換為十進位制數字的話,它就會被當作數字索引來處理。

var a = [];
a["13"] = 1;
console.log(a.length); //14
console.log(a); //[ <13 empty items>, 1 ]
複製程式碼

相關文章