在前端開發中,常常會遇到要判斷數組中是否存在某個元素。其實判斷的方式有不少種,咱們一個一個來了解下。javascript
咱們先來定義一個數組:前端
const arr = [ 13, false, 'abcd', undefined, 13, null, NaN, [1, 2], { a: 123 }, () => Date.now(), new Date('2021/03/04'), new RegExp('abc', 'ig'), Symbol('sym'), ];
在這個數組中,咱們包含了好幾種類型:number, boolean, string, undefined, null, array, object, Date, Symbol 等。其中數字 13 出現了 2 次。java
咱們最熟悉的就是indexOf
了,畢竟他出現的早,兼容性也好,使用起來也很方便。數組
若是存在該元素,則返回第一次出現的索引值;若整個數組不存在該元素,則返回-1。函數
只要判斷返回的數據是否是-1,就能知道數組中是否包含該元素。測試
arr.indexOf(13) >= 0; // true, indexOf返回0 arr.indexOf(2) >= 0; // false, indexOf返回-1
與 indexOf 對應的是 lastIndexOf,從最後往前查找元素,若存在該元素,則返回在數組中的最後一個的索引;若不存在該元素,則返回-1。3d
arr.lastIndexOf(13) >= 0; // true, lastIndexOf返回4, 最後一次出現的索引
兩個方法在判斷變量是否存在時,調用方式是同樣的。code
indexOf 和 lastIndexOf 還有第 2 個可選參數 fromIndex,用來表示從哪一個索引開始進行搜索。regexp
在 indexOf 中,若 fromIndex 超過數組的長度,則直接返回-1,若爲負數,則從最後往前數幾個索引(arr.length-Math.abs(fromIndex)),而後開始日後搜索。對象
在 lastIndexOf 中,若 fromIndex 達到或超過數組的長度,則搜索整個數組;若爲負數,則從最後往前數幾個索引(arr.length-Math.abs(fromIndex)),而後開始往前搜索,若負數的絕對值超過了數組的長度,則直接返回-1。
arr.indexOf(13, 2); // 4, 從索引值2開始日後查找,首先找到的13的索引值爲4 arr.indexOf(13, -10); // 4, 從索引值1(11-10)開始日後檢索 arr.lastIndexOf(13, 2); // 0, 從索引值2往前開始搜索 arr.lastIndexOf(13, -2); // 4, 從索引值9(11-2)開始往前搜索
並且 indexOf 和 lastIndexOf 中採用的是嚴格相等的方式(===)來判斷的。
arr.indexOf(null); // 5, 在null的前面有幾個假值false和undefined,也能準確找到null的索引值
indexOf 主要是爲了查找元素所在的索引值,只是咱們能夠用返回的索引值來間接判斷數組中是否存在該元素。
而在 ES7(ES2016)中添加的includes
方法,就是專門用來判斷元素是否存在的。返回值爲 true 或者 false,true 表示存在,false 表示不存在,簡單明瞭。
arr.includes(13); // true arr.includes('abc'); // false arr.includes(false); // true, 存在false元素
同時,includes 方法中也存在第 2 個可選參數 fromIndex,fromIndex 的用法與 indexOf 中的同樣。若 fromIndex 超過數組的長度,則直接返回-1,若爲負數,則從最後往前數幾個索引(arr.length-Math.abs(fromIndex)),而後開始日後搜索。
arr.includes(13, 5); // false, 從索引值5開始日後檢索,沒檢索到
到目前爲止,後面的幾種類型,例如 Array, Object, Date 和 Symbol,咱們都沒判斷呢。咱們如今來判斷下後面的幾個元素:
// 使用indexOf判斷 arr.indexOf(NaN); // -1 arr.indexOf([1, 2]); // -1 arr.indexOf({ a: 123 }); // -1 arr.indexOf(() => Date.now()); // -1 arr.indexOf(new Date('2021/03/04')); // -1 arr.indexOf(new RegExp('abc', 'ig')); // -1 arr.indexOf(Symbol('sym')); // -1 // 使用includes判斷 arr.includes(NaN); // false arr.includes([1, 2]); // false arr.includes({ a: 123 }); // false arr.includes(() => Date.now()); // false arr.includes(new Date('2021/03/04')); // false arr.includes(new RegExp('abc', 'ig')); // false arr.includes(Symbol('sym')); // false
結局很慘,這幾種元素在數組中都沒有檢索到。但是實際上在數組中都是真實存在的。
這是由於 indexOf 和 includes 都是採用嚴格相等的方式(===)來斷定的。
NaN === NaN; // false, 兩個NaN永遠也不會相等 [1, 2] === [1, 2]; // false, 每一個聲明出來的數組都有單獨的存儲地址 {a: 123} === {a: 123}; // false, 同數組 new Date('2021/03/04')===new Date('2021/03/04'); // false, 看着日期是相同的,可是用new出來的對象進行比較的,確定是不相等的 Symbol('sym')===Symbol('sym'); // Symbol類型的出現就是爲了不衝突創造出來的類型,括號裏的屬性僅是爲了方便描述而已
針對這些沒法被檢索的類型,咱們就須要本身寫函數來判斷特殊的類型了。
find()和 findIndex()容許咱們經過回調函數,來自定義判斷的方式。
find()
方法返回數組中知足提供的測試函數的第一個元素的值。不然返回 undefined
。
find()方法沒法檢測數組中的 undefined 元素。
由於不存在和存在 undefined 元素,find()方法都會返回 undefined。這裏咱們就要考慮其餘方式了,稍後再講。
arr.find((item) => item === 13); // 13, 找到了元素13 arr.find((item) => item === 3); // undefined, 沒找到元素3 arr.find((item) => item === undefined); // undefined, 也不知道是找到了仍是沒找到
對於上面稍微複雜點的類型,咱們就須要特殊的判斷了:
arr.find((item) => typeof item === 'number' && isNaN(item)); // NaN // array和object類型進行比較時,狀況很複雜,由於每一個元素的類型都沒法肯定 // 若是肯定都是基本類型,如string, number, boolean, undefined, null等,能夠將其轉爲字符串再比較 // 轉字符串的方式也不少,如JSON.stringify(arr), arr.toString(), arr.split('|')等 // 複雜點的,只能一項一項比較,或者使用遞歸 arr.find((item) => item.toString() === [1, 2].toString()); // [1, 2] arr.find((item) => JSON.stringify(item) === JSON.stringify({ a: 123 })); // {a: 123} arr.find((item) => { if (typeof item === 'function') { return item.toString() === (() => Date.now()).toString(); } return false; }); // () => Date.now() arr.find((item) => { if (item instanceof Date) { return item.toString() === new Date('2021/03/04').toString(); } return false; }); // Thu Mar 04 2021 00:00:00 GMT+0800 arr.find((item) => { if (item instanceof RegExp) { return item.toString() === new RegExp('abc', 'ig').toString(); } return false; }); // /abc/gi // Symbol確實無法比較,只能比較描述是否同樣 arr.find((item) => { if (typeof item === 'symbol') { return item.toString() === Symbol('sym').toString(); } return false; }); // Symbol(sym)
上面的判斷代碼在後面的方法也將會使用到。
咱們在上面對比了多種類型元素的比較,稍微來總結下。
先來定義一個函數:
const compare = (x, y) => {};
對於元素是 string, number, boolean, undefined, null 等基本類型的,能夠直接進行比較:
const compare = (x, y) => { return x === y; };
NaN 用 typeof 來判斷是 number 類型,但 NaN 不與任何數字相等,包括它本身。
const compare = (x, y) => { if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) { return true; } return x === y; };
這些類型的,能夠將變量轉爲字符串進行比較:
const compare = (x, y) => { if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) { return true; } if ( (typeof x === 'function' && typeof y === 'function') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number) ) { return x.toString() === y.toString(); } return x === y; };
對於 object 類型和 array 的,咱們能夠將每一項拆開,而後利用上面的方式再挨個兒比較。
若是還要判斷數組中是否存在 undefined,咱們可使用findIndex()
方法。
findIndex()
方法返回數組中知足提供的測試函數的第一個元素的索引。若沒有找到對應元素則返回-1。
arr.findIndex((item) => item === undefined); // 3 arr.findIndex((item) => item === 3); // -1, 沒有找到數字3
其餘數據格式的判斷,與上面的 find()同樣。
some()
方法測試數組中是否是至少有 1 個元素經過了被提供的函數測試。它返回的是一個 Boolean 類型的值。
注意:若是用一個空數組進行測試,在任何狀況下它返回的都是
false
。
some()方法與 find()方法的使用方式同樣,只不過 some()方法返回的是 boolean 類型的數據。
arr.some((item) => item === false); // true arr.some((item) => item === undefined); // true arr.some((item) => typeof item === 'number' && isNaN(item)); // true arr.some((item) => item === 3); // false, 不存在數字3 arr.some((item) => { if (item instanceof Date) { return item.toString() === new Date('2021/03/04').toString(); } return false; }); // true
filter()
方法建立一個新數組, 其包含經過所提供函數實現的測試的全部元素。
不管找到幾個元素或者沒有元素,filter()方法都是會返回一個數組,數組中的數據就是咱們想要的元素。
arr.filter((item) => item === false); // 1 arr.filter((item) => item === undefined); // 1 arr.filter((item) => typeof item === 'number' && isNaN(item)); // 1 arr.filter((item) => item === 13); // 2 arr.filter((item) => item === 3); // 0 arr.filter((item) => { if (item instanceof Date) { return item.toString() === new Date('2021/03/04').toString(); } return false; }); // 1
所以咱們能夠經過該數組的長度,來判斷原數組是否包含咱們想要的元素。
查找數組中元素的方式有不少,咱們能夠數組中元素的格式,來選擇更合適的方式。若是都是一些基本類型,建議優先選擇使用includes()
方法;若是格式比較複雜的,建議選擇使用some()
方法。這兩個方法都是直接返回 boolean 類型,無需更多的轉換便可直接使用方法的結果。