JS中的數組過濾,從簡單篩選到多條件篩選

在上家公司工做的時候,有一個需求是在前端部分完成篩選功能,一次拿到全部數據,而後根據條件篩選。一般狀況下篩選是後臺給接口,在數據量不大的狀況下,也有人可能會遇到前端篩選這樣的狀況,特別寫了這篇文章分享給你們,有問題請指出,互相學習。javascript

通常狀況下的單條件篩選,數組的filter方法就可以知足需求,本文討論的重點是多條件下的複合篩選,並列出了幾個相關知識點。前端

如下是不少個🌰🌰🌰🌰java

// 這個是例子中的被篩選數組
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是否爲目標名字便可git

// 根據單個名字篩選
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循環能夠用數組的一些遍歷方法替代,代碼能夠更簡化,示例就是大概表達個意思。github

// 根據多個名字篩選
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: 數組的深拷貝與淺拷貝

最近參與一些前端的面試工做,深拷貝與淺拷貝是我最愛問的問題之一。一個問題就考察了數據類型,數組操做,遞歸算法等。

由於數組是js裏的引用類型,單純複製時複製的是其引用關係。在對獲取的數據進行篩選時,我並不但願影響原始數據,因此我要用到「深拷貝」獲得與原始數據數據結構徹底相同又相互獨立的數據,而不是隻複製其引用關係。

// 我經常使用方法,若是項目很大,不推薦
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);
}

複製代碼

完!

相關文章
相關標籤/搜索