巧技拾遺 | JavaScript 中 Array.every 和 Array.map 的巧妙結(jié)合
這幾天在跟著學一點 vue3 + TypeScript 中表單驗證的實例,看到一個實現(xiàn),覺得非常巧妙。
需求概述
我們有一個列表 funcArr ,里面存放函數(shù),比如 funcArr = [ func1, func2, ... ] 。這些函數(shù)都是 () => boolean 即無參數(shù)、返回值為布爾值的。
我們期望在提交表單時,執(zhí)行 funcArr 中的每一個函數(shù),如果這些函數(shù)都通過驗證,則我們的主邏輯獲取到 true ,否則是 false 。
樸素版本
- func1 = () => { console.log(1); return true; }
- func2 = () => { console.log(2); return false; }
- func3 = () => { console.log(3); return true; }
- funcArr = [func1, func2, func3];
- result = true;
- for (var i = 0; i < funcArr.length; i ++ )
- {
- if (!funcArr[i]( "i")) result = false;
- }
- console.log(result)
輸出是:
- > 1
- > 2
- > 3
- > false
這種做法顯然有點瞎扯了,完全沒有用到 JavaScript 特性和函數(shù)式編程的思想。
Array.prototype.every()
一般來講,有上述需求,我們用 Array.prototype.every()[1] 函數(shù)來解決。
根據(jù) MDN 的描述:every用于檢測是否每個函數(shù)都通過,并且最終返回 一個 布爾值。
于是:
- func1 = () => { console.log(1); return true; }
- func2 = () => { console.log(2); return false; }
- func3 = () => { console.log(3); return true; }
- funcArr = [func1, func2, func3];
- result = funcArr.every(func => func());
- console.log(result)
輸出:
- > 1
- > 2
- > false
可以注意到一個現(xiàn)象:當every發(fā)現(xiàn)有一個元素沒有通過驗證時,它就不再繼續(xù)檢查其他元素了。
結(jié)合 map()
有時候,我們的 funcArr 中的函數(shù),不僅僅是單純的返回一個布爾值,其中還有其他邏輯如修改一些響應式變量的作用。
因此,我們希望 every 能夠執(zhí)行完畢所有函數(shù),即便發(fā)現(xiàn)其中某一個是 return false 了的。
考慮使用 map 。
- func1 = () => { console.log(1); return true; }
- func2 = () => { console.log(2); return false; }
- func3 = () => { console.log(3); return true; }
- funcArr = [func1, func2, func3];
- result = funcArr.map(func => func()).every(res => res);
- console.log(result)
輸出:
- > 1
- > 2
- > 3
- > false
every在其中的作用,像是一個漏斗,把所有的值依次過濾,有一個 false 就返回 false ,否則是 true 。