1. 簡介
conditionOperat 可以對一系列復(fù)雜的條件進行邏輯運算,條件可以是基本類型的數(shù)據(jù),也可以是個函數(shù),甚至可以是個異步條件,即 Promise;或者是個條件集,條件集也可以再嵌套條件集;可以指定條件之間的邏輯關(guān)系,如:與、或、非;
如果您在使用的過程中遇到了問題,或者有好的建議和想法,您都可以通過以下方式聯(lián)系我,期待與您的交流:
- 給該倉庫提交 issues
- 給我 Pull requests
2. 特性
可以指定條件條件表達式的間的邏輯關(guān)系:與、或、非;
條件表達式可以任意層級嵌套,即:條件集 可以 嵌套 條件集;
短路運算
在對條件表達式進行運算的過程中,如果運算中途已經(jīng)能夠確認(rèn)最終的運算結(jié)果,則便會停止對剩余表達式的計算,并返回計算結(jié)果;-
簡單優(yōu)先
為了提高運算效率,除了加入了短路運算的特性外,還加入了簡單優(yōu)先的計算原則,即:對于同一層級表達式,會按照下面的順序優(yōu)先計算:- BaseCondition | FunCondition: 除了 異步條件 PromCondition、條件集 ConditionSet 以外的所有其它數(shù)據(jù)類型的條件表達式,這些條件會被當(dāng)作布爾值來計算;
- ConditionSet : 條件集;
- PromCondition : 異步條件;
3. 安裝方式
目前,安裝方式有以下幾種:
方式1:通過 npm 安裝
npm install --save condition-operat
方式2:直接下載原代碼
您可直接從 git倉庫 下載代碼文件;
倉庫里包含了 源碼 和 編譯后的代碼文件 :
- conditionOperat 的源碼文件是
src/conditionOperat有 TypeScript 版本 和 JavaScript 版本; - conditionOperat 的編譯后的文件是
dist/conditionOperat.js;
您可以直接把任一 源碼 或 編譯后 的文件拷貝到您的項目中去;然后使用如下代碼在您的項目中引入 conditionOperat:
import { conditionOperat , create } from "path/to/package/conditionOperat";
或者
import conditionOperat from "path/to/package/conditionOperat";
方式3:通過<script>標(biāo)簽引入
您可直接下載 git倉庫 中的 dist/conditionOperat.js 文件,然后使用如下代碼引用 和 使用 conditionOperat:
引用 conditionOperat.js
<script src="path/to/package/conditionOperat.js"></script>
使用全局的 conditionOperat() 或 快捷工具 conditionOperat.create()
<script>
// 使用全局的 conditionOperat()
var condExpr = [true,false,true];
conditionOperat(condExpr);
// 使用快捷工具
var operatWith = conditionOperat.create(condExpr);
</script>
4. 教程
如果需要了解詳細(xì)的接口信息,請到 API接口文檔
4.1. 最簡單的使用
// 求表達式 true 的值
conditionOperat(true); //結(jié)果: true
4.2. 與運算
對于基本類型的數(shù)據(jù)(如:boolean、number、string、symbol、undefined、null )都會被作為布爾值來對待,即會被簡單的轉(zhuǎn)為布爾類型;
// 對一組表達式做 與 運算;
var condExpr = [
true,
false,
"字符串會作為布爾值對待",
34,
0, // 相當(dāng)于 false
];
conditionOperat(condExpr); //結(jié)果: false
或者
// 對一組表達式做 與 運算
var condExpr = [
true,
false,
true
];
condExpr.rel = "and"; // rel 可設(shè)置為 "and" (與運算) 或 "or"(或運算), 如果沒設(shè)置 rel ,則默認(rèn)會用 與運算 "and"
conditionOperat(condExpr); //結(jié)果: false
4.3. 或運算
// 對一組表達式做 或 運算
var condExpr = [
true,
false,
true
];
condExpr.rel = "or"; //設(shè)置 數(shù)組中元素之間關(guān)系為 或 ; 即:對所有元素進行 或運算
conditionOperat(condExpr); //結(jié)果: true
4.4. 先或后非
var condExpr = [
true,
false,
true
];
condExpr.rel = "or"; //設(shè)置:數(shù)組中元素之間關(guān)系為 或 ; 即:對所有元素進行 或運算
condExpr.not = true; //設(shè)置:對運算結(jié)果 取反,即 對所有元素進行 或運算之后 再取反
conditionOperat(condExpr); //結(jié)果: false
4.5. 表達式可以嵌套
//里面的表達式
var innerExpr = [
false,
true
];
innerExpr.rel = "or";
var condExpr = [
true,
innerExpr, // 表達式可以嵌套表達式
true
];
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.6. 函數(shù)類型的表達式
函數(shù)也可作為表達式,運算時會將函數(shù)的返回值作新的表達式重新計算,如果函數(shù)返回的還是函數(shù),則會對該返回的函數(shù)繼續(xù)運算;
函數(shù)也可以返回一個 Promise,針對 Promise類型表達式的運算方式,詳見[Promise類型的表達式][]
var condExpr = [
function(){return false}, //表達式可以是個返回 另一個表達式的函數(shù)
function(){return "返回其它類型的值"},
function(){
return ()=>{return 5}
}, //函數(shù)表達式 可以返回 另一個函數(shù)表達式
true, //表達式的類型可以混合使用
];
conditionOperat(condExpr); //結(jié)果: false
在執(zhí)行條件運算 conditionOperat() 時,你也可以設(shè)置函數(shù)條件在被調(diào)用時的 this 值 和 參數(shù),如下:
// 驗證名字
function verifyName(phoneNum,gender){
var name = this.value;
return name.trim().length > 0
}
//驗證手機號
function verifyPhone(phoneNum,gender){
return /\d{11}/.test(phoneNum)
}
// 驗證性別
function verifyGender(phoneNum,gender){
return /^男|女$/.test(gender)
}
// 條件表達式:名字、手機號、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
// 獲取保存名字的輸入框的dom元素 來作為 函數(shù)條件的 this 的值;
var thisValue = document.getElementById("nameInput");
// 給函數(shù)條件傳遞兩個參數(shù):手機號 和 性別
var args = ["17639609033","男"];
// conditionOperat() 的第一個參數(shù)是 條件表達式,第二個參數(shù)是 函數(shù)條件的 this 值,第三個參數(shù)是 函數(shù)條件 的參數(shù)數(shù)組
conditionOperat(condExpr,thisValue,args);
注意:
thisValue 和 args 會被應(yīng)用到所有的 函數(shù)條件,包括那些 運算過程 中產(chǎn)生的函數(shù)條件,比如:函數(shù)條件返回的函數(shù)條件、異步條件決議時傳遞出的 函數(shù)條件
4.7. 異步表達式
Promise 也可以作為表達式,當(dāng) Promise 作為表達式時,會根據(jù) resolve 的值來進行計算,如果 Promise 是被 reject 了,則會被作為 假 false 來處理;
Promise 決議的值也可以是其它復(fù)雜的條件表達式,如:函數(shù)、數(shù)組(條件集)等等;
var condExpr = [
new Promise(function (resolve, reject) {
setTimeout( ()=>{
resolve(false)
},1000)
}),
new Promise(function (resolve, reject) {
setTimeout( resolve,2000,false)
}),
new Promise(function (resolve, reject) {
setTimeout( ()=>{
reject("reject的參數(shù)") //被 reject 的 Promise 會被作為 假值 來對待
},3000)
}),
];
condExpr.rel = "or"; //設(shè)置各 Promise 之間是 或 的關(guān)系
conditionOperat(condExpr).then(function (res) {
console.log(res)
}); //3秒后輸出: false
4.8. 非運算
對于任何對象(比如:普通對象、函數(shù)、Promise、數(shù)組 等等),都可以通過向其添加 not 屬性來設(shè)置 非運算;設(shè)置非運算后,會先對 該對象進行求值,然后再對求得的值取反;
4.8.1. 普通對象的非運算
/*
先對對象 求值,然后再取反;
由于對象 轉(zhuǎn)成布爾后 為 true,對 true 取反后 為 false ,所以 對 條件表達式 {not:true} 求值后 得 false
*/
var condExpr = {not:true};
conditionOperat(condExpr); //結(jié)果: false
4.8.2. 函數(shù)的非運算
/*
先對函數(shù) 求值,然后再取反;
先對函數(shù) 求值,得 true,再取反,得 false
*/
var condExpr = function(){
return true
};
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.8.3. 異步非運算
/*
先對 Promise 求值,然后再取反;
選對 Promise 求值,得到異步的值 true,再取反后,得 false
*/
var condExpr = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(true)
},1000)
});
condExpr.not = true;
conditionOperat(condExpr).then(function(vlaue){
console.log(value); //結(jié)果: false
});
4.8.4. 條件集的非運算
/*
先運算 數(shù)組中所有元素相或 的值,為 true,然后再取反,得 false
*/
var condExpr = [
true,
0,
{}
];
condExpr.rel = "or"; //設(shè)置 或 關(guān)系
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.9. 異步表達式與其它類型的表達式混合使用
Promise類型的條件表達工也可以與其它類型的條件表達式混合使用;
對于帶有 Promise 類型的條件表達式,conditionOperat(condExpr) 返回的結(jié)果可能是 布爾值,也可能是 Promise ;這取決于通過 非 Promise 的表達式是否能求出 condExpr 的值,如果能,則返回的是布爾值,如果不能,則 condExpr 的值只能依賴于 其中的 Promise 表達式,則 conditionOperat(condExpr) 就會返回一個 Promise ;
如果 返回的是 Promise ,側(cè) Promise 決義后的值值便是表達式 condExpr 的運算結(jié)果;
var condExpr = [
true, //布爾值作為條件,直接表示條件成立或失敗
false,
3.5, //數(shù)字會被轉(zhuǎn)為布爾類型;
0, //0 相當(dāng)于 false
"字符串也可作為表達式", //字符串也會被轉(zhuǎn)為布爾類型;
{}, //對象會被轉(zhuǎn)為布爾類型;
//對于任何對象(比如:函數(shù)、Promise、數(shù)組 等等),都可以通過向其添加 not 屬性來設(shè)置 非運算;
{not:true}, //對象會被轉(zhuǎn)為 true,由于本身的 not 屬性為 true,所以,還會對該對象本盤的值 true 再進行一次 非運算,所以該表達式的值為 false
function () {return false}, //函數(shù)作為條件,會根據(jù)函數(shù)的返回值作為該條件的計算結(jié)果
function () {return [false,45]}, //函數(shù)也可以返回 條件集
[
"", // 空字符串相當(dāng)于 false
{mes:"對象也可作為表達式"}, //對象也可以作為條件,它會被當(dāng)作真值來對待,即相當(dāng)于 true
new Promise(function (resolve, reject) {
setTimeout( ()=> {
resolve(true)
},500)
}), // Promise 作為表達式,當(dāng)被計算時,會根據(jù) Promise 被 resolve 時的 value 來作為 計算結(jié)果;
new Promise(function (resolve, reject) {
var funCond = ()=>{return false};
setTimeout( ()=> {
resolve(funCond)
},500)
}) // Promise 作為表達式,當(dāng)被計算時,會根據(jù) Promise 被 resolve 時的 value 來作為 計算結(jié)果,如果 value 仍是復(fù)雜的表達式(比如:函數(shù)),還會繼續(xù)計算;
], // 條件集,也就是數(shù)組,也可以作為條件表達式,會根據(jù) 該條件集的計算結(jié)果作為 該條件集 的結(jié)果
new Promise(function (resolve, reject) {
setTimeout( ()=> {
reject("reject會被認(rèn)為返回了假值")
},300)
}) // 如果 Promise 被 reject 了,則 該 Promise 表達式的計算結(jié)果為 false
];
condExpr.rel = "or"; //設(shè)置條件集中所有條件表達式的關(guān)系為 或
condExpr.not = true; //對 條件集中所有表達式 進行 或運算(由rel屬性指定) 之后,再對其結(jié)果取反,即:再進行 非運算;
/*
調(diào)用 conditionOperat 函數(shù)對 條件表達式 condExpr 進行求值;
返回的結(jié)果可能是 布爾值,也可能是 Promise ;這取決于通過 非 Promise 的表達式是否能求出 condExpr 的值,如果能,則返回的是布爾值,如果不能,則 condExpr 的值只能依賴于 其中的 Promise 表達式,則 conditionOperat(condExpr) 就會返回一個 Promise ;
如果 返回的是 Promise ,側(cè) Promise 決義后的值值便是表達式 condExpr 的運算結(jié)果
*/
var res = conditionOperat(condExpr)
if (res instanceof Promise){
res.then((value)=>{
console.log("condExpr條件表達式的值是:",value);
})
}else {
console.log("condExpr條件表達式的值是:",res);
}
4.10. 快捷工具
條件運算函數(shù) conditionOperat(condExpress:CondExpression,thisValue?:ThisValue, args?:Args):OperatedResult 可接收如下三個參數(shù)
- condExpress : CondExpression 條件表達式
- thisValue ?: any 設(shè)置條件表達式中 函數(shù)條件 的 this 的值
- args ?: any[] 設(shè)置條件表達式中 函數(shù)條件 的 參數(shù)序列
這三個參數(shù)中,只有 條件表達式 condExpress 是必須參數(shù);
有些時候,我們可能經(jīng)常需要 對同一條件表達式 condExpress 進行運算,只是傳不同的 thisValue 或 args ;
比如:對表單中若干輸入框進行驗證,這些輸入框的驗證條件是一定的,但每次提交表單時,各個輸入框的值是不一樣的,對于這樣的場景,我們每次進行條件運算時,都要傳入同一 條件表達式 condExpress 和 包含各個輸入框值的 args conditionOperat(condExpress,null, args) ,如果 每次表單的dom的結(jié)構(gòu)都是一樣的,也可以將 表單的 dom 對象 作為 thisValue 參數(shù),讓 函數(shù)條件 自動獲取對應(yīng)的輸入框的值并驗證,這樣,我們不用每次再分別取各個輸入框的值了,只需要給 conditionOperat() 傳 條件表達式 condExpress 和 thisValue 就行了,如 conditionOperat(condExpress,thisValue) ;
盡管這樣,每次條件運算,還是需要傳入一樣的 條件表達式,這是重復(fù)的操作;
為了解決這類問題,我封裝了一個工具函數(shù) create() ,它根據(jù)給定的參數(shù),來創(chuàng)建專門用來接收剩余參數(shù)的條件運算函數(shù);
有兩種方式可以訪問到 create() 函數(shù):
- 直接導(dǎo)入create函數(shù)
import { create,conditionOperat } from "condition-operat"; - 通過 conditionOperat 的 create 方法來訪問:
conditionOperat.create(options);
create()的使用示例如下:
// 驗證名字
function verifyName(target){
return target.name.trim().length > 0
}
//驗證手機號
function verifyPhone(target){
return /\d{11}/.test(target.phoneNum)
}
// 驗證性別
function verifyGender(target){
return /^男|女$/.test(target.gender)
}
// 條件表達式:名字、手機號、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
/**
* 創(chuàng)建條件表達式 condExpr 和 thisValue (值為 `null`) 的快捷函數(shù) operatWith ;
*
* 因為創(chuàng)建 `operatWith()` 時 給 `create()` 傳了兩個選項 expr 和 "this" ,還剩余一個選項 args 參數(shù)沒有傳,
* 所以 這個 operatWith() 快捷函數(shù)只接收一個參數(shù),即 args ;
*/
var operatWith = create({
expr:condExpr,
"this":null
});
// 被測試的目標(biāo)
var target = {
name:"郭斌勇",
gender:"男",
phoneNum:""
};
// 傳入 args
operatWith([target]); //結(jié)果:false
或者
// 驗證名字
function verifyName(){
var inputDom = this.elements.name;
var name = inputDom.value;
return name.trim().length > 0
}
//驗證手機號
function verifyPhone(){
var inputDom = this.elements.phoneNum;
var phoneNum = inputDom.value;
return /\d{11}/.test(phoneNum)
}
// 驗證性別
function verifyGender(){
var inputDom = this.elements.gender;
var gender = inputDom.value;
return /^男|女$/.test(gender)
}
// 條件表達式:名字、手機號、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
/**
* 創(chuàng)建條件表達式 condExpr 的快捷函數(shù) operatWith ;
*
* 因為創(chuàng)建 `operatWith()` 時 給 `create()` 傳了一個選項 expr ,還剩余二個選項 "this" 和 args 選項沒有傳,
* 所以 這個 operatWith() 快捷函數(shù)可以接收二個參數(shù),即 "this" 和 args ; 但本示例中的 函數(shù)條件 只用到了 "this" 選項 ,沒有用到 args ,所以,在使用 operatWith() 時,只需要給其傳一個參數(shù) thisValue 即可;
*/
var operatWith = create({expr:condExpr});
// 被測試的目標(biāo)
var thisValue = document.getElementById("form");
// 傳入 thisValue 參數(shù)
operatWith(thisValue);
其中,當(dāng)傳給 create() 的選項只包含 表達式 condExpr 時,可以直接將表達式 condExpr 作為參數(shù)傳給 create() ,如 create(condExpr)
有您的支持,我會在開源的道路上,越走越遠(yuǎn) 贊賞碼