判斷數(shù)組中存在元素的多種方式

在前端開發(fā)中,經(jīng)常會遇到要判斷數(shù)組中是否存在某個元素蕾管,我們來了解下各個判斷的方式螃诅。

在前端開發(fā)中啡氢,經(jīng)常會遇到要判斷數(shù)組中是否存在某個元素。其實判斷的方式有很多種术裸,我們一個一個來了解下倘是。
我們先來定義一個數(shù)組:

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'),
];

在這個數(shù)組中,我們包含了好幾種類型:number, boolean, string, undefined, null, array, object, Date, Symbol等袭艺。其中數(shù)字 13 出現(xiàn)了 2 次搀崭。

  1. indexOf
    我們最熟悉的就是indexOf了,畢竟他出現(xiàn)的早猾编,兼容性也好门坷,使用起來也很方便宣鄙。

如果存在該元素,則返回第一次出現(xiàn)的索引值默蚌;若整個數(shù)組不存在該元素冻晤,則返回-1。
1.1 使用方式
只要判斷返回的數(shù)據(jù)是不是-1绸吸,就能知道數(shù)組中是否包含該元素鼻弧。

arr.indexOf(13) >= 0; // true, indexOf返回0
arr.indexOf(2) >= 0; // false, indexOf返回-1

indexOf 對應(yīng)的是 lastIndexOf,從最后往前查找元素锦茁,若存在該元素攘轩,則返回在數(shù)組中的最后一個的索引;若不存在該元素码俩,則返回-1度帮。

arr.lastIndexOf(13) >= 0; // true, lastIndexOf返回4, 最后一次出現(xiàn)的索引

兩個方法在判斷變量是否存在時,調(diào)用方式是一樣的稿存。
1.2 第 2 個可選參數(shù)
indexOflastIndexOf還有第 2 個可選參數(shù) fromIndex笨篷,用來表示從哪個索引開始進(jìn)行搜索。

indexOf中瓣履,若fromIndex 超過數(shù)組的長度率翅,則直接返回-1,若為負(fù)數(shù)袖迎,則從最后往前數(shù)幾個索引(arr.length-Math.abs(fromIndex))冕臭,然后開始往后搜索。

lastIndexOf 中燕锥,若 fromIndex 達(dá)到或超過數(shù)組的長度辜贵,則搜索整個數(shù)組;若為負(fù)數(shù)归形,則從最后往前數(shù)幾個索引(arr.length-Math.abs(fromIndex))托慨,然后開始往前搜索,若負(fù)數(shù)的絕對值超過了數(shù)組的長度连霉,則直接返回-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)開始往前搜索

而且indexOflastIndexOf中采用的是嚴(yán)格相等的方式(===)來判斷的跺撼。

arr.indexOf(null); // 5, 在null的前面有幾個假值false和undefined窟感,也能準(zhǔn)確找到null的索引值
  1. includes
    indexOf主要是為了查找元素所在的索引值,只是我們可以用返回的索引值來間接判斷數(shù)組中是否存在該元素歉井。

而在 ES7(ES2016)中添加的includes方法柿祈,就是專門用來判斷元素是否存在的。返回值為true或者 falsetrue表示存在躏嚎,false表示不存在蜜自,簡單明了。

arr.includes(13); // true
arr.includes('abc'); // false
arr.includes(false); // true, 存在false元素

同時卢佣,includes 方法中也存在第 2 個可選參數(shù)fromIndex重荠,fromIndex的用法與indexOf 中的一樣。若 fromIndex 超過數(shù)組的長度虚茶,則直接返回-1戈鲁,若為負(fù)數(shù),則從最后往前數(shù)幾個索引(arr.length-Math.abs(fromIndex))嘹叫,然后開始往后搜索婆殿。

arr.includes(13, 5); // false, 從索引值5開始往后檢索,沒檢索到

到目前為止罩扇,后面的幾種類型婆芦,例如 Array, Object, DateSymbol,我們都沒判斷呢喂饥。我們現(xiàn)在來判斷下后面的幾個元素:

// 使用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

結(jié)局很慘消约,這幾種元素在數(shù)組中都沒有檢索到⊙鲂海可是實際上在數(shù)組中都是真實存在的荆陆。

這是因為indexOfincludes 都是采用嚴(yán)格相等的方式(===)來判定的滩届。

NaN === NaN; // false, 兩個NaN永遠(yuǎn)也不會相等
[1, 2] === [1, 2]; // false, 每個聲明出來的數(shù)組都有單獨的存儲地址
{a: 123} === {a: 123}; // false, 同數(shù)組
new Date('2021/03/04')===new Date('2021/03/04'); // false, 看著日期是相同的集侯,但是用new出來的對象進(jìn)行比較的,肯定是不相等的
Symbol('sym')===Symbol('sym'); // Symbol類型的出現(xiàn)就是為了避免沖突創(chuàng)造出來的類型帜消,括號里的屬性僅是為了方便描述而已

針對這些無法被檢索的類型棠枉,我們就需要自己寫函數(shù)來判斷特殊的類型了。

  1. find 和 findIndex
    find()findIndex()允許我們通過回調(diào)函數(shù)泡挺,來自定義判斷的方式辈讶。
    3.1 find 方法
    find() 方法返回數(shù)組中滿足提供的測試函數(shù)的第一個元素的值。否則返回 undefined娄猫。

find()方法無法檢測數(shù)組中的undefined 元素贱除。

因為不存在和存在undefined 元素,find()方法都會返回undefined媳溺。這里我們就要考慮其他方式了月幌,稍后再講。

arr.find((item) => item === 13); // 13, 找到了元素13
arr.find((item) => item === 3); // undefined, 沒找到元素3
arr.find((item) => item === undefined); // undefined, 也不知道是找到了還是沒找到

對于上面稍微復(fù)雜點的類型悬蔽,我們就需要特殊的判斷了:

arr.find((item) => typeof item === 'number' && isNaN(item)); // NaN

// array和object類型進(jìn)行比較時扯躺,情況很復(fù)雜,因為每個元素的類型都無法確定
// 如果確定都是基本類型,如string, number, boolean, undefined, null等录语,可以將其轉(zhuǎn)為字符串再比較
// 轉(zhuǎn)字符串的方式也很多倍啥,如JSON.stringify(arr), arr.toString(), arr.split('|')等
// 復(fù)雜點的,只能一項一項比較澎埠,或者使用遞歸
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)

上面的判斷代碼在后面的方法也將會使用到。
3.2 兩個元素進(jìn)行比較
我們在上面對比了多種類型元素的比較蒲稳,稍微來總結(jié)下彼宠。

先來定義一個函數(shù):

const compare = (x, y) => {};

3.2.1 基本類型
對于元素是 string, number, boolean, undefined, null等基本類型的,可以直接進(jìn)行比較:

const compare = (x, y) => {
  return x === y;
};

3.2.2 NaN 數(shù)據(jù)
NaNtypeof來判斷是number類型弟塞,但 NaN不與任何數(shù)字相等凭峡,包括它自己。

const compare = (x, y) => {
  if (typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y)) {
    return true;
  }
  return x === y;
};

3.2.3 Function 與 Date 與 RegExp
這些類型的决记,可以將變量轉(zhuǎn)為字符串進(jìn)行比較:

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的摧冀,我們可以將每一項拆開,然后利用上面的方式再挨個兒比較系宫。
3.3 findIndex 方法
如果還要判斷數(shù)組中是否存在undefined索昂,我們可以使用findIndex()方法。
findIndex()方法返回數(shù)組中滿足提供的測試函數(shù)的第一個元素的索引扩借。若沒有找到對應(yīng)元素則返回-1椒惨。

arr.findIndex((item) => item === undefined); // 3
arr.findIndex((item) => item === 3); // -1, 沒有找到數(shù)字3

其他數(shù)據(jù)格式的判斷,與上面的find()一樣潮罪。

  1. some
    some()方法測試數(shù)組中是不是至少有 1 個元素通過了被提供的函數(shù)測試康谆。它返回的是一個 Boolean類型的值。
    注意:如果用一個空數(shù)組進(jìn)行測試嫉到,在任何情況下它返回的都是false沃暗。
    some()方法與find()方法的使用方式一樣,只不過 some()方法返回的是 boolean類型的數(shù)據(jù)何恶。
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, 不存在數(shù)字3
arr.some((item) => {
  if (item instanceof Date) {
    return item.toString() === new Date('2021/03/04').toString();
  }
  return false;
}); // true
  1. filter
    filter()方法創(chuàng)建一個新數(shù)組, 其包含通過所提供函數(shù)實現(xiàn)的測試的所有元素孽锥。

無論找到幾個元素或者沒有元素,filter()方法都是會返回一個數(shù)組细层,數(shù)組中的數(shù)據(jù)就是我們想要的元素惜辑。

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

因此我們可以通過該數(shù)組的長度,來判斷原數(shù)組是否包含我們想要的元素疫赎。

  1. 總結(jié)
    查找數(shù)組中元素的方式有很多盛撑,我們可以數(shù)組中元素的格式,來選擇更合適的方式虚缎。如果都是一些基本類型撵彻,建議優(yōu)先選擇使用includes()方法钓株;如果格式比較復(fù)雜的,建議選擇使用some()方法陌僵。這兩個方法都是直接返回 boolean類型轴合,無需更多的轉(zhuǎn)換即可直接使用方法的結(jié)果。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碗短,一起剝皮案震驚了整個濱河市受葛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偎谁,老刑警劉巖总滩,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巡雨,居然都是意外死亡闰渔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門铐望,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冈涧,“玉大人,你說我怎么就攤上這事正蛙《焦” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵乒验,是天一觀的道長愚隧。 經(jīng)常有香客問我,道長锻全,這世上最難降的妖魔是什么狂塘? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮虱痕,結(jié)果婚禮上睹耐,老公的妹妹穿的比我還像新娘辐赞。我一直安慰自己部翘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布响委。 她就那樣靜靜地躺著新思,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赘风。 梳的紋絲不亂的頭發(fā)上夹囚,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音邀窃,去河邊找鬼荸哟。 笑死假哎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鞍历。 我是一名探鬼主播舵抹,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼劣砍!你這毒婦竟也來了惧蛹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤刑枝,失蹤者是張志新(化名)和其女友劉穎香嗓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體装畅,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡靠娱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掠兄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饱岸。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徽千,靈堂內(nèi)的尸體忽然破棺而出苫费,到底是詐尸還是另有隱情,我是刑警寧澤双抽,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布百框,位于F島的核電站,受9級特大地震影響牍汹,放射性物質(zhì)發(fā)生泄漏铐维。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一慎菲、第九天 我趴在偏房一處隱蔽的房頂上張望嫁蛇。 院中可真熱鬧,春花似錦露该、人聲如沸睬棚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抑党。三九已至,卻和暖如春撵摆,著一層夾襖步出監(jiān)牢的瞬間底靠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工特铝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留暑中,地道東北人壹瘟。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像鳄逾,于是被迫代替她去往敵國和親俐筋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容