巧技拾遺 | JavaScript 中 Array.every 和 Array.map 的巧妙結合
這幾天在跟著學一點 vue3 + TypeScript 中表單驗證的實例,看到一個實現,覺得非常巧妙。
需求概述
我們有一個列表 funcArr ,里面存放函數,比如 funcArr = [ func1, func2, ... ] 。這些函數都是 () => boolean 即無參數、返回值為布爾值的。
我們期望在提交表單時,執行 funcArr 中的每一個函數,如果這些函數都通過驗證,則我們的主邏輯獲取到 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 特性和函數式編程的思想。
Array.prototype.every()
一般來講,有上述需求,我們用 Array.prototype.every()[1] 函數來解決。
根據 MDN 的描述:every用于檢測是否每個函數都通過,并且最終返回 一個 布爾值。
于是:
- 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
可以注意到一個現象:當every發現有一個元素沒有通過驗證時,它就不再繼續檢查其他元素了。
結合 map()
有時候,我們的 funcArr 中的函數,不僅僅是單純的返回一個布爾值,其中還有其他邏輯如修改一些響應式變量的作用。
因此,我們希望 every 能夠執行完畢所有函數,即便發現其中某一個是 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 。