JS關於Array的includes()的坑
JQuery的val()搭配includes()導致的血案

JavaScript的includes()

  • 想知道Array中有沒有包含某元素,可能會想到indexOf()方法,然而他回傳的是index位置或-1還要判斷有點麻煩,而includes()可以直接返回true或false更直觀一點

  • 但是要注意如果是Object組成的Array的話可能會有坑,例如我想找array中有沒有name=‘李四’的元素,乍看是這樣:

let array = [{name: '張三'}, {name: '李四'}, {name: '王五'}];

console.log(array.indexOf({name: '李四'}) !== -1);  // false
console.log(array.includes({name: '李四'}));        // false
  • 實際上比較的是記憶體指向的位置,例如:
let man = {name: '李四'};
let array = [{name: '張三'}, man, {name: '王五'}];

console.log(array.indexOf(man) !== -1);  // true
console.log(array.includes(man));        // true
  • 真的要查找Object組成的Array中是否有符合某屬性的元素,可以這樣用:
let array = [{name: '張三'}, {name: '李四'}, {name: '王五'}];

array.includes(array.filter(e => e.name === '李四')[0])
  • 另外這個indexOf()比較的底層其實是相當於’===’,也就是說包含類型,例如ajax返回的是Object的類型,比較的是String類型的話也會找不到
    • 還有NaN也是
const arrNum = ['12',23,45,67,8,9,NaN];
console.log(arrNum.includes(NaN)) // true
console.log(arrNum.indexOf(NaN)); // -1 
  • 總之includes()更好用

JQuery的val()搭配includes()導致的血案

前情提要,我有一個allObjectList是物件組成的清單(裡面的object有數字的id)

mySelect是一個<select>的html元素,選項是id,可多選的下拉清單(也可以單選)

  • 我想在allObjectList中篩選出使用者有選中的id構成一個新的ObjectList,所以就這樣寫
    • 用$("#mySelect").val()獲取選中的id,因為select的value用這個方法會拿到string,所以在includes()比較時也把id轉成string來比較
var newObjectList = allObjectList.filter(function(obj) {
return $("#mySelect").val().includes(obj.id.toString());
});
  • 乍一看運作起來也沒問題。然而當只有單選且id為兩位數以上就出事了
  • 因為.val()這個方法用在select上,當有多選時他會得到array,但是只有單選時卻是得到"單個物件"。例如使用者單選中id=“12”,此時我的方法實際上變成
"12".includes()
  • 符合條件的變成"1"、“2”、“12”,我想要的只有"12"但是卻把"1"、“2"也一起得到了
  • 坑點就在於.includes()這個方法不只array可以用,string也可以用(就是把string拆成數組)我是真的沒想到

教訓

  • 老實一點把.val()獲取到的東西先強制轉成Number Array,就可以杜絕這個隱患
var newObjectList = allObjectList.filter(function(obj) {
return convertToNumberArray($("#mySelect").val()).includes(obj.id);
});

/**
 * Convert Array of Strings to Array of Numbers
 */
function convertToNumberArray(input) {
    if (Array.isArray(input)) {
        var result = input.map(function(item) {
            return parseInt(item, 10);
        });
        return result;
    } else {
        return Array.of(parseInt(input, 10));
    }
}

上次修改於 2022-06-20