Array的屬性和方法

屬性 length

length 屬性可獲得數組的長度,即數組中值的個數。數組的長度是比數組最大索引值多一的數。

let arr = [1, 2, 3, 4]
arr.length      //  4;

如果給 length 屬性賦值,指定的數組長度小於原數組長度,會縮短數組。

let arr = [1, 2, 3, 4]
arr.length = 3;
arr             // [1, 2, 3]

length 設爲 0,可以清空數組。

let arr = [1, 2, 3, 4]
arr.length = 0;
arr              // []

方法

靜態方法

1. Array.isArray()

Array.isArray() 方法返回一個布爾值,表示參數是否爲數組。它可以彌補 typeof 運算符的不足。

let arr = [1, 2, 3];

typeof arr           // "object"
Array.isArray(arr)   // true

2. Array.from()

Array.from() 方法用於將兩類對象轉爲真正的數組:類數組對象和可遍歷(iterable)的對象(包括 ES6 新增的數據結構 Set 和 Map)。返回值是新數組。

let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 };

// ES5的寫法
var arr1 = [].slice.call(arrayLike);   // ['a', 'b', 'c']

// ES6的寫法
let arr2 = Array.from(arrayLike);      // ['a', 'b', 'c']

只要是部署了 Iterator 接口的數據結構,Array.from 都能將其轉爲數組。

Array.from('hello')    // ['h', 'e', 'l', 'l', 'o']

let namesSet = new Set(['a', 'b'])
Array.from(namesSet)   // ['a', 'b']

任何有 length 屬性的對象,即類數組對象,都可以通過 Array.from() 方法轉爲數組。

Array.from({ length: 3 });    // [ undefined, undefined, undefined ]

Array.from() 還可以接受第二個參數,作用類似於數組的 map 方法,用來對每個元素進行處理,將處理後的值放入返回的數組。

Array.from(arrayLike, x => x * x);
// 等同於
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)   // [1, 4, 9]

Array.from() 的第三個參數,用來綁定 this

應用

取出一組 DOM 節點的文本內容。

let spans = document.querySelectorAll('span.name');

// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);

// Array.from()
let names2 = Array.from(spans, s => s.textContent)

將數組中布爾值爲 false 的成員轉爲 0

Array.from([1, , 2, , 3], (n) => n || 0)   // [1, 0, 2, 0, 3]

返回各種數據的類型。

function typesOf () {
  return Array.from(arguments, value => typeof value)
}
typesOf(null, [], NaN)   // ['object', 'object', 'number']

將字符串轉爲數組,然後返回字符串的長度。因爲它能正確處理各種 Unicode 字符,可以避免 JS 將大於 \uFFFFUnicode 字符,算作兩個字符的 bug。

function countSymbols(string) {
  return Array.from(string).length;
}

3. Array.of()

Array.of() 方法用於將一組值,轉換爲數組。

Array.of(3, 11, 8)     // [3,11,8]
Array.of(3)            // [3]
Array.of(3).length     // 1

Array.of() 總是返回參數值組成的數組。如果沒有參數,就返回一個空數組。

Array.of()            // []
Array.of(undefined)   // [undefined]
Array.of(1)           // [1]

Array.of() 方法可以用下面的代碼模擬實現。

function ArrayOf(){
  return [].slice.call(arguments);
}

實例方法

1. valueOf(),toString()

valueOf() 方法是一個所有對象都擁有的方法,表示對該對象求值,不同對象的valueOf() 方法不盡一致。數組的 valueOf 方法是 Array 構造函數的原型上的方法,覆蓋了 ObjectvalueOf() 方法,返回數組本身。

let arr = [1, 2, 3];
arr.valueOf()    // [1, 2, 3]

toString() 方法也是對象的通用方法。數組的 toString 方法是 Array 構造函數的原型上的方法,覆蓋了 ObjecttoString() 方法,返回數組的字符串形式。相當於調用 join() 方法,將數組轉換爲字符串,用逗號連接。

let arr = [1, 2, 3];
arr.toString()     // "1,2,3"

let arr = [1, 2, 3, [4, 5, 6]];
arr.toString()     // "1,2,3,4,5,6"

2. push(),pop()

push() 方法用於在數組的末端添加一個或多個元素,並返回添加新元素後的數組長度。

該方法會直接改變原數組。

let arr = [];

arr.push(1)           // 1
arr.push('a')         // 2
arr.push(true, {})    // 4
arr                   // [1, 'a', true, {}]

pop() 方法用於刪除數組的最後一個元素,一次只能刪一項。並返回被刪除的該元素。

該方法會直接改變原數組。

let arr = ['a', 'b', 'c'];

arr.pop()    // 'c'
arr          // ['a', 'b']

對空數組使用 pop() 方法,不會報錯,而是返回 undefined

[].pop()     // undefined

push()pop() 結合使用,就構成了“後進先出”的棧結構(stack)。

let arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();   // 3 是最後進入數組的,但是最早離開數組。
arr          // [1, 2]

3. shift(),unshift()

shift() 方法用於刪除數組的第一個元素,一次只能刪一項。並返回被刪除的該元素。

該方法會直接改變原數組。

let arr = ['a', 'b', 'c'];

arr.shift()   // 'a'
arr           // ['b', 'c']

push()shift() 結合使用,就構成了“先進先出”的隊列結構(queue)。

let arr = [];
arr.push(1, 2);
arr.push(3);
arr.shift();   // 1 是最先進入數組的,也最早離開數組。
arr            // [2, 3]

unshift() 方法用於在數組的第一個位置添加一個或多個元素,並返回添加新元素後的數組長度。

該方法會直接改變原數組。

let arr = ['a', 'b', 'c'];

arr.unshift('x');      // 4
arr.unshift('y', 'z')  // 6
arr                    // ["y", "z", "x", "a", "b", "c"]

4. join()

join() 方法以指定參數作爲分隔符,將所有數組成員連接爲一個字符串返回。如果不提供參數,默認用逗號分隔。

該方法不改變原數組。

let arr = [1, 2, 3, 4];

arr.join(' ')     // '1 2 3 4'
arr.join(' | ')   // "1 | 2 | 3 | 4"
arr.join('~')     // '1~2~3~4'
arr.join()        // "1,2,3,4"

如果數組成員是 undefinednull空位 ,會被轉成空字符串。

[undefined, null].join('#')   // '#'
['a',, 'b'].join('-')         // 'a--b'

通過 call 方法,這個方法也可以用於字符串或類數組對象。

Array.prototype.join.call('hello', '-')    // "h-e-l-l-o"

let obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')        // 'a-b'

5. concat()

concat() 方法用於多個數組的合併。它將新數組的成員,添加到原數組成員的後面,然後返回一個新數組。參數設置非常靈活,可以是數組變量,也可以是字符串或數組字面量。

該方法不改變原數組。


['hello'].concat(['world'], ['!'])  // ["hello", "world", "!"]
[].concat({a: 1}, {b: 2})           // [{ a: 1 }, { b: 2 }]
[1, 2, 3].concat(4, 5, 6)           // [1, 2, 3, 4, 5, 6]

let arr = [2,3];
[1].concat(arr)                     // [1, 2, 3]

concat() 方法是“淺拷貝”,拷貝的是對象的引用。

let obj = { a: 1 };
let newArray = [].concat(obj);
newArray[0].a                    // 1
obj.a = 2                        // 2
newArray[0].a                    // 2

6. reverse()

reverse() 方法用於顛倒排列數組元素,返回改變後的數組。

該方法會直接改變原數組。

let arr = ['a', 'b', 'c'];

arr.reverse()     // ["c", "b", "a"]
arr               // ["c", "b", "a"]

7. slice()

slice(start, end) 方法用於提取目標數組中選中的部分作爲一個新的數組返回。

該方法不改變原數組。

參數

a. slice(start, end),從下標 start 開始截取到下標 end 的元素,包含 start 不包含 end

let arr = ['a', 'b', 'c'];
arr.slice(1, 2)     // ["b"]
arr.slice(2, 6)     // ["c"]

b. slice(start),只有 start 一個參數表示從包含 start 的下標開始截取後面所有的元素。

let arr = ['a', 'b', 'c'];
arr.slice(1)    // ["b", "c"]

c. slice(),沒有參數,則相當於從下標 0 開始截取後面所有的元素,實際上等於返回一個原數組的拷貝。

let arr = ['a', 'b', 'c'];
arr.slice(0)    // ["a", "b", "c"]
arr.slice()     // ["a", "b", "c"]

d. slice(-start, -end),參數可以用負數。表示倒數計算的位置。-1 表示倒數計算的第一個位置,依次向前類推。

let arr = ['a', 'b', 'c'];
arr.slice(-2)         // ["b", "c"]
arr.slice(-2, -1)     // ["b"]

e. 如果第一個參數大於等於數組長度,或者第二個參數小於第一個參數,則返回空數組。

let arr = ['a', 'b', 'c'];
arr.slice(4)           // []
arr.slice(2, 1)        // []

slice() 方法的一個重要應用,是通過 call 方法,將類數組對象轉爲真正的數組。

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })  // ['a', 'b']

Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);

8. splice()

splice() 方法是一個多功能方法,根據參數的不同可以插入、刪除、替換元素,返回值是被刪除的元素組成的數組。

該方法會直接改變原數組。

arr.splice(start, count, addElement1, addElement2, ...);

參數

a. arr.splice(start) 1個參數是拆分,等同於將原數組在指定位置拆分成兩個數組。刪除下標之後的全部值。包含 start

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(3)     // ['d', 'e', 'f']
arr               // ['a', 'b', 'c']

b. arr.splice(start, count) 2個參數是刪除,第二個參數是刪除的個數,相當於從 start 開始,刪除第二個參數指定的元素個數。

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(4, 2)    // ["e", "f"] 下標 4 開始刪除 2 項
arr                 // ["a", "b", "c", "d"]

c. arr.splice(start, count, ...) 更多參數是替換,表示從 start 開始,刪除 count 項,然後將後面的參數作爲新元素插入原數組中,返回值是被刪除的元素。

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
arr.splice(4, 2, 1, 2)   // ["e", "f"]
arr                     // ["a", "b", "c", "d", 1, 2]

d. arr.splice(start, 0, ...) 第二個參數爲0時,表示插入,從 start 開始,刪除 0 項,並在 start 之前添加新元素。返回空數組。

let arr = ['a', 'b', 'c', 'd'];
arr.splice(2, 0, 1, 2)  // []
arr                     // ["a", "b", 1, 2, "c", "d"]

e. arr.splice(-start, ...) 起始位置 start 如果是負數,就表示從倒數位置開始進行相關操作。

let arr = ['a', 'b', 'c', 'd'];
arr.splice(-2, 2)     // ["c", "d"]

9. sort()

sort() 方法對數組成員進行排序,默認按照字符順序排序,會將數字隱式轉換爲字符串排序。直接返回改變後的原數組。

該方法會直接改變原數組。

let arr = ['d', 'c', 'b', 'a'];
arr.sort()    // ["a", "b", "c", "d"]
arr           // ["a", "b", "c", "d"]

會將數字隱式轉換爲字符串排序。

let arr=[2,3,45,12,78,67,155]
arr.sort()    // [12, 155, 2, 3, 45, 67, 78]

自定義排序,可以傳入一個函數作爲參數。

let arr=[2,3,45,12,78,67,155]
arr.sort(function(a,b){ return a-b })   //  [2, 3, 12, 45, 67, 78, 155]

sort 的參數函數本身接受兩個參數 ab,表示進行比較的兩個數組成員。如果該函數的返回值 >0,那麼 b 排在 a 的前面;=0,位置不變;<0a 排到 b 的前面。

[{ name: "張三", age: 30 },
  { name: "李四", age: 24 },
  { name: "王五", age: 28 }
].sort(function (o1, o2) {
  return o1.age - o2.age;
})

// [
//   { name: "李四", age: 24 },
//   { name: "王五", age: 28 },
//   { name: "張三", age: 30 }
// ]

10. map()

map() 方法將數組的所有成員依次傳入參數函數,然後把每一次的執行結果組成一個新數組返回。

該方法不改變原數組。

let numbers = [1, 2, 3];
numbers.map(function (n) {
  return n + 1;
});        // [2, 3, 4]
numbers    // [1, 2, 3]

map() 方法接受一個函數作爲參數。該函數調用時,map方法向它傳入三個參數:第一個爲當前進入函數的數組元素,第二個爲當前元素的下標,第三個爲原始數組。只有第一個是必須的。

[1, 2, 3].map(function(elem, index, arr) {
  return elem * index;
});            // [0, 2, 6]

如果數組有空位,map() 方法的回調函數在這個位置不會執行,會跳過數組的空位。但不會跳過 undefinednull

let f = function (n) { return 'a' };

[1, undefined, 2].map(f)   // ["a", "a", "a"]
[1, null, 2].map(f)        // ["a", "a", "a"]
[1, , 2].map(f)            // ["a", , "a"]

map() 方法還可以接受第二個參數,用來綁定回調函數內部的 this 變量

let arr = ['a', 'b', 'c'];

[1, 2].map(function (e) {
  return this[e];
}, arr)        // ['b', 'c']

11. forEach()

forEach() 方法與 map() 方法很相似,也是對數組的所有成員依次執行參數函數。但是,forEach() 方法不返回值,只用來操作數據。這就是說,如果數組遍歷的目的是爲了得到返回值,那麼使用 map() 方法,否則使用 forEach() 方法。

forEach() 的用法與 map() 方法一致,參數是一個函數,該函數同樣接受三個參數:當前元素、當前下標、整個數組。同樣也會跳過數組的空位。但不會跳過 undefinednull

var log = function (n) { console.log(n + 1); };

[1, undefined, 2].forEach(log)   // 2   // NaN  // 3
[1, null, 2].forEach(log)        // 2   // 1    // 3
[1, , 2].forEach(log)           // 2    // 3

forEach() 方法也可以接受第二個參數,綁定參數函數的 this 變量。

let out = [];

[1, 2, 3].forEach(function(elem) {
  this.push(elem * elem);
}, out);

out     // [1, 4, 9]

注意,forEach() 方法無法中斷執行,總是會將所有成員遍歷完。如果希望符合某種條件時,就中斷遍歷,要使用 for 循環。

let arr = [1, 2, 3];

for (let i = 0; i < arr.length; i++) {
  if (arr[i] === 2) break;
  console.log(arr[i]);
}
// 1

12. filter()

filter() 方法用於過濾數組成員,滿足條件的成員組成一個新數組返回。它的參數是一個函數,所有數組成員依次執行該函數,返回結果爲 true 的成員組成一個新數組返回。

該方法不改變原數組。

[1, 2, 3, 4, 5].filter(function (elem) {
  return (elem > 3);
})         // [4, 5]

let arr = [0, 1, 'a', false];
arr.filter(Boolean)     // [1, "a"]

filter() 方法的參數函數可以接受三個參數:當前元素、當前下標、整個數組。

[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
  return index % 2 === 0;
});       // [1, 3, 5]

filter() 方法還可以接受第二個參數,用來綁定參數函數內部的 this 變量。

let obj = { MAX: 3 };
let myFilter = function (item) {
  if (item > this.MAX) return true;
};

let arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj)    // [8, 4, 9]

13. some(),every()

這兩個方法類似“斷言”(assert),返回一個布爾值,表示判斷數組成員是否符合某種條件。

它們接受一個函數作爲參數,所有數組成員依次執行該函數。該函數接受三個參數:當前元素、當前下標和整個數組。然後返回一個布爾值。

some() 方法是隻要一個成員的返回值是 true,則整個 some() 方法的返回值就是 true,否則返回 false

let arr = [1, 2, 3, 4, 5];
arr.some(function (elem, index, arr) {
  return elem >= 3;
});          // true

every() 方法是所有成員的返回值都是 true,整個every() 方法才返回 true,否則返回 false

let arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) {
  return elem >= 3;
});          // false

注意,對於空數組,some() 方法返回 falseevery() 方法返回 true,回調函數都不會執行。

function isEven(x) { return x % 2 === 0 }

[].some(isEven)       // false
[].every(isEven)      // true

some()every() 方法還可以接受第二個參數,用來綁定參數函數內部的 this 變量。

14. reduce(),reduceRight()

reduce() 方法和 reduceRight() 方法依次處理數組的每個成員,最終累計爲一個值。它們的差別是,reduce 是從左到右處理(從第一個元素到最後一個元素),reduceRight 則是從右到左(從最後一個元素到第一個元素),其他完全一樣。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  console.log(a, b);
  return a + b;
})        //  15
// 1 2
// 3 3
// 6 4
// 10 5

reduce() 方法和 reduceRight() 方法的第一個參數都是一個函數。該函數接受以下四個參數。前兩個是必須的,後兩個是可選的。

  • 累積變量,依次爲上一輪的返回值,初始值默認爲數組的第一個元素,可通過參數傳入指定的初始變量。
  • 當前變量,默認爲數組的第二個元素,當累積變量有指定初始值時,當前變量爲第一個元素。
  • 當前變量的下標,默認爲 1,當累積變量有指定初始值時,下標爲 0。
  • 原數組

reduce() 方法和 reduceRight() 方法的第二個參數是對累積變量指定初值。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  return a + b;
}, 10);       // 25

指定累積變量相當於設定了默認值,對於處理空數組尤其有用。

function add(prev, cur) { return prev + cur; }
[].reduce(add)        // 報錯
[].reduce(add, 1)     // 1  永遠返回初始值,不會執行函數

reduceRight() 是從右到左依次執行函數。

 function subtract(prev, cur) { return prev - cur; }
 
 [3, 2, 1].reduce(subtract)         // 0
 [3, 2, 1].reduceRight(subtract)    // -4

應用 由於這兩個方法會遍歷數組,所以實際上還可以用來做一些遍歷相關的操作。

找出字符長度最長的數組成員。

function findLongest(entries) {
  return entries.reduce(function (longest, entry) {
    return entry.length > longest.length ? entry : longest;
  }, '');
}

findLongest(['aaa', 'bb', 'c'])     // "aaa"

將二維數組轉化爲一維

[[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
    return a.concat(b);
},[])          // [0, 1, 2, 3, 4, 5]

數組去重

let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current)=>{
    if(init.length===0 || init[init.length-1]!==current){
        init.push(current);
    }
    return init;
}, [])         //[1,2,3,4,5]

按屬性對object分類

let people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];

function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    let key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}

groupBy(people, 'age');
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }

參考鏈接:Array.prototype.reduce()

15. indexOf(),lastIndexOf()

indexOf() 方法返回參數在數組中第一次出現的位置,如果沒有出現則返回-1。

let arr = ['a', 'b', 'c'];
arr.indexOf('b')    // 1
arr.indexOf('y')    // -1

indexOf() 方法還可以接受第二個參數,表示搜索的開始位置。

['a', 'b', 'c'].indexOf('a', 1)    // -1

lastIndexOf() 方法返回參數在數組中最後一次出現的位置,如果沒有出現則返回-1。

let arr = [2, 5, 9, 2];
arr.lastIndexOf(2)     // 3
arr.lastIndexOf(7)     // -1

注意,這兩個方法不能用來搜索 NaN 的位置,即它們無法確定數組成員是否包含 NaN。這是因爲這兩個方法內部,使用嚴格相等運算符(===)進行比較,而 NaN 是唯一一個不等於自身的值。

[NaN].indexOf(NaN)        // -1
[NaN].lastIndexOf(NaN)    // -1

16. copyWithin()

copyWithin() 方法,在當前數組內部,將指定位置的成員複製到其他位置(會覆蓋原有成員),然後返回當前數組。包含 start 不包含 end

該方法會直接改變原數組。

Array.prototype.copyWithin(target, start, end)

接受三個參數:

  • target(必需):從該位置開始替換數據。如果爲負值,表示倒數。
  • start(可選):從該位置開始讀取數據,默認爲 0。如果爲負值,表示倒數。
  • end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
[1, 2, 3, 4, 5].copyWithin(0, 3)   // [4, 5, 3, 4, 5]

上面代碼表示將從下標 3 到數組結束的元素(4 和 5),複製到從下標 0 開始的位置,結果覆蓋了原來的 1 和 2。

[1, 2, 3, 4, 5].copyWithin(0, 3, 4)      // [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)    // [4, 2, 3, 4, 5]
[].copyWithin.call({length: 5, 3: 1}, 0, 3)  // {0: 1, 3: 1, length: 5}

17. find(),findIndex()

find() 方法用於找出第一個符合條件的數組元素。它的參數是一個回調函數,所有數組元素依次執行該回調函數,直到找出第一個返回值爲 true 的元素,然後返回該元素。如果沒有符合條件的元素,則返回 undefined

[1, 4, -5, 10].find((n) => n < 0)    // -5

find() 方法的回調函數可以接受三個參數,依次爲當前元素、當前下標和原數組。

[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
})        // 10

findIndex() 方法的用法與 find() 方法非常類似,返回第一個符合條件的數組元素的位置,如果所有元素都不符合條件,則返回 -1。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
})       // 2

這兩個方法都可以接受第二個參數,用來綁定回調函數的 this 對象。

function f(v){ return v > this.age; }
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);      // 26

另外,這兩個方法都可以可以藉助 Object.is() 方法識別數組的 NaN,彌補了 indexOf() 方法的不足。

[NaN].indexOf(NaN)       // -1

[NaN].findIndex(y => Object.is(NaN, y))   // 0

18. fill()

fill() 方法使用給定值,填充一個數組。

['a', 'b', 'c'].fill(7)    // [7, 7, 7]

new Array(3).fill(7)       // [7, 7, 7]

fill() 方法還可以接受第二個和第三個參數,用於指定填充的起始位置和結束位置。

['a', 'b', 'c'].fill(7, 1, 2)    // ['a', 7, 'c']

注意,如果填充的類型爲對象,那麼被賦值的是同一個內存地址的對象,而不是深拷貝對象。

let arr = new Array(3).fill({name: "Mike"});
arr[0].name = "Ben";
arr    // [{name: "Ben"}, {name: "Ben"}, {name: "Ben"}]

let arr = new Array(3).fill([]);
arr[0].push(5);
arr    // [[5], [5], [5]]

19. includes()

includes() 方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes() 方法類似。

[1, 2, 3].includes(2)        // true
[1, 2, 3].includes(4)        // false
[1, 2, NaN].includes(NaN)    // true

該方法的第二個參數表示搜索的起始位置,默認爲0。如果第二個參數爲負數,則表示倒數的位置,如果這時它大於數組長度(比如第二個參數爲-4,但數組長度爲3),則會重置爲從0開始。

[1, 2, 3].includes(3, 3);    // false
[1, 2, 3].includes(3, -1);   // true

沒有該方法之前,我們通常使用數組的 indexOf() 方法,檢查是否包含某個值。

if (arr.indexOf(el) !== -1) {
  // ...
}

indexOf() 方法內部使用嚴格相等運算符(===)進行判斷,這會導致對 NaN 的誤判。includes() 使用的是不一樣的判斷算法,就沒有這個問題。

[NaN].indexOf(NaN)     // -1
[NaN].includes(NaN)    // true

20. flat(),flatMap()

flat() 用於將多維數組變成一維數組。返回一個新數組。

該方法不改變原數組。

[1, 2, [3, 4]].flat()   // [1, 2, 3, 4]

flat() 默認只會“拉平”一層,如果想要“拉平”多層的嵌套數組,可以將 flat() 方法的參數寫成一個整數,表示想要拉平的層數,默認爲 1。

[1, 2, [3, [4, 5]]].flat()     // [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)    // [1, 2, 3, 4, 5]

如果不管有多少層嵌套,都要轉成一維數組,可以用 Infinity 關鍵字作爲參數。

[1, [2, [3]]].flat(Infinity)   // [1, 2, 3]

如果原數組有空位,flat() 方法會跳過空位。

[1, 2, , 4, 5].flat()          // [1, 2, 4, 5]

flatMap() 方法對原數組的每個元素執行一個函數(相當於執行Array.prototype.map()),然後對返回值組成的數組執行 flat() 方法。返回新數組。

該方法不改變原數組。

[2, 3, 4].flatMap((x) => [x, x * 2])   // [2, 4, 3, 6, 4, 8]
//  相當於 [[2, 4], [3, 6], [4, 8]].flat()

flatMap() 只能展開一層數組。

[1, 2, 3, 4].flatMap(x => [[x * 2]])   // [[2], [4], [6], [8]]
//  相當於 [[[2]], [[4]], [[6]], [[8]]].flat()

flatMap() 方法的參數是一個遍歷函數,該函數可以接受三個參數,分別是當前數組元素、當前數組元素的下標(從零開始)、原數組。

flatMap() 方法還可以有第二個參數,用來綁定遍歷函數裏面的 this

arr.flatMap(function callback(currentValue[, index[, array]]) {
  // ...
}[, thisArg])

鏈式使用

上面這些數組方法之中,有不少返回的還是數組,所以可以鏈式使用。

var users = [
  {name: 'tom', email: '[email protected]'},
  {name: 'peter', email: '[email protected]'}
];

users
.map(function (user) {
  return user.email;
})
.filter(function (email) {
  return /^t/.test(email);
})
.forEach(function (email) {
  console.log(email);
});
// "[email protected]"

參考鏈接:
Array對象
數組的擴展

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