JS实现数组过滤从简单到多条件筛选

作者:异步漫步时间:2026-10-24 13:08:12浏览:602

本文详细讲解JavaScript中数组过滤的实现方式,从基础的单条件筛选进阶至复杂的多条件复合筛选。通过解析filter、find、Object.keys等核心API,结合深拷贝与falsy值判断,提供高效的前端数据筛选方案,帮助开发者优化前端性能并处理复杂业务逻辑。

在前端开发场景中,有时需要一次性获取所有数据并在客户端完成筛选逻辑。尽管常规做法是通过后端接口进行数据过滤,但在数据量较小的情况下,前端筛选也是一种可行的方案。本文旨在分享这一实现思路,欢迎交流指正。

对于简单的单条件筛选,直接使用数组的filter方法即可满足需求。本文的重点在于探讨多条件下的复合筛选逻辑,并梳理其中涉及的关键技术点。

接下来通过多个具体示例进行演示。


// 这个是例子中的被筛选数组
var aim = [
    {name:'Anne', age: 23, gender:'female'},
    {name:'Leila', age: 16, gender:'female'},
    {name:'Jay', age: 19, gender:'male'},
    {name:'Mark', age: 40, gender:'male'}
]

单条件单数据筛选

若需根据单个名字进行筛选,可直接使用filter方法,判断对象的name属性是否等于目标名字即可。


// 根据单个名字筛选
function filterByName(aim, name) {
    return aim.filter(item => item.name == name)
}
// 输入 aim 'Leila' 期望输出为 [{name:'Leila', age: 16, gender:'female'}]
console.log(filterByName(aim,'leila'))

单条件多数据筛选

当需要根据多个名字进行筛选时,可以使用for循环遍历目标数组,并利用find方法查找匹配项后push到结果数组中。使用find方法的优势在于,即使存在重名情况,也能准确获取所需结果。虽然for循环可以被其他数组遍历方法替代以简化代码,但此处示例旨在表达核心逻辑。


// 根据多个名字筛选
function filterByName1(aim, nameArr) {
    let result = []
    for(let i = 0; i < nameArr.length; i++) {
        result.push(aim.find(item => item.name = nameArr[i]))
    }
    return result
}
// 输入 aim ['Anne','Jay'] 
//期望输出为 [{name:'Anne', age: 23, gender:'female'},{name:'Jay', age: 19, gender:'male'}]
console.log(filterByName1(aim,['Leila','Jay']))
// 有BUG 改进后

多条件单数据筛选

若需根据单个名字或单个年龄进行筛选,仍可使用filter方法,此时判断条件之间为“或”的关系,即满足任一条件即可返回该数据。


// 根据名字或者年龄筛选
function filterByName2(aim, name, age) {
    return aim.filter(item => item.name == name || item.age == age)
}
console.log(filterByName2(aim,'Leila',19))

多条件多数据筛选

起初尝试使用双层for循环实现,但发现性能较差且未达预期效果。经过调整,提出以下筛选算法:首先将筛选条件封装在一个对象中,利用Object对象的keys方法获取条件名(如name、age、gender等)。随后使用filter方法对目标数据进行筛选,具体示例如下:根据名字和年龄进行多元素筛选。


//根据名字和年龄多元素筛选
export function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters)
  // filters all elements passing the criteria
  return array.filter((item) => {
    // dynamically validate all filter criteria
    return filterKeys.every(key => {
        //ignore when the filter is empty Anne
      if(!filters[key].length) return true
      return !!~filters[key].indexOf(item[key])
    })
  })
}
/*
 * 这段代码并非我原创,感兴趣的可以去原作者那里点个赞
 * 作者是:@author https://gist.github.com/jherax
 * 这段代码里我只加了一行,解决部分筛选条件清空时候整体筛选失效的问题
 */

var filters = {
    name:['Leila', 'Jay'],
    age:[]
}
/* 结果:
 * [{name: "Leila", age: 16, gender: "female"},
 *  {name: "Jay", age: 19, gender: "male"}]
 */

在实现中,判断每条数据的name值是否存在于filters.name数组中,若存在则返回true;同时,若filters.age为空数组,则直接返回true。空数组在此处模拟了age条件被清空的状态,此时仍能正确获取筛选后的数据。

知识点1: Object.key() 获取数组索引或者对象属性


var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); 
// ["0", "1", "2"]


var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); 
// ["0", "1", "2"]


var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); 
// ["2", "7", "100"] 猜猜为啥?

知识点2: js里的falsy

falsy值包括:0、false、""、null、undefined、NaN。

在判断语句中,仅有上述6种情况会被转换为false,其余所有值均会被转换为true。


var a;
if(a!=null&&typeof(a)!=undefined&&a!=''){
    //a有内容才执行的代码  
}

if(!!a){
    //a有内容才执行的代码...  
}

知识点3: Array.every 与 Array.some的区别

在遍历数组时,两者的行为如下:

  • Array.every的条件关系为「与」,即所有条件全为true时返回true,只要有一个false则立即返回false。
  • Array.some的条件关系为「或」,即只要有一个条件为true则返回true,仅当所有条件全为false时才返回false。

以下通过具体示例进行说明。


// 判断每个名字都为Anne?
let dataEvery = aim.every(item => item.name === 'Anne') // false
let dataEvery = aim.some(item => item.name === 'Anne') // true

// 判断每个名字都是字符串?
let dataEvery = aim.every(item => typeof item.name === 'string') // true
let dataEvery = aim.some(item => typeof item.name === 'string') // true

知识点4: 数组的深拷贝与浅拷贝

在前端面试中,深拷贝与浅拷贝是常见考点,涉及数据类型、数组操作及递归算法等多个方面。

由于数组是JavaScript中的引用类型,直接复制仅复制其引用关系。在筛选数据时,为避免影响原始数据,需要使用「深拷贝」生成与原始数据结构完全相同且相互独立的新数据,而非仅仅复制引用。


// 我常用方法,如果项目很大,不推荐
let obj1 = JSON.parse(JSON.stringify(obj))

// deepclone
function deepClone(o1, o2) {
    for (let k in o2) {
        if (typeof o2[k] === 'object') {
            o1[k] = {};
            deepClone(o1[k], o2[k]);
        } else {
            o1[k] = o2[k];
        }
    }
}

想一想:递归算法的优化

该知识点与本文主题关联不大,此前提及可能造成误导,特此说明。

此内容源自掘金小册《前端面试指南》,在讲解算法时提及递归优化。虽然尚未在实际项目中应用,但值得尝试。例如斐波那契数列的计算,可以对比使用缓存与不使用缓存时的运算次数差异,建议在浏览器中自行测试。


let count = 0;
function fn(n) {
    let cache = {};
    function _fn(n) {
        if (cache[n]) {
            return cache[n];
        }
        count++;
        if (n == 1 || n == 2) {
            return 1;
        }
        let prev = _fn(n - 1);
        cache[n - 1] = prev;
        let next = _fn(n - 2);
        cache[n - 2] = next;
        return prev + next;
    }
    return _fn(n);
}

let count2 = 0;
function fn2(n) {
    count2++;
    if (n == 1 || n == 2) {
        return 1;
    }
    return fn2(n - 1) + fn2(n - 2);
}

至此,关于JS实现数组过滤从简单到多条件筛选的介绍完毕。如需了解更多JS数组过滤相关内容,可搜索本站历史文章或继续浏览后续文章,感谢支持。

作者最新文章