1. 簡(jiǎn)介
conditionOperat 可以對(duì)一系列復(fù)雜的條件進(jìn)行邏輯運(yùn)算,條件可以是基本類(lèi)型的數(shù)據(jù)哭廉,也可以是個(gè)函數(shù)脊僚,甚至可以是個(gè)異步條件,即 Promise遵绰;或者是個(gè)條件集,條件集也可以再嵌套條件集增淹;可以指定條件之間的邏輯關(guān)系椿访,如:與、或虑润、非成玫;
如果您在使用的過(guò)程中遇到了問(wèn)題,或者有好的建議和想法拳喻,您都可以通過(guò)以下方式聯(lián)系我哭当,期待與您的交流:
- 給該倉(cāng)庫(kù)提交 issues
- 給我 Pull requests
2. 特性
可以指定條件條件表達(dá)式的間的邏輯關(guān)系:與、或冗澈、非钦勘;
條件表達(dá)式可以任意層級(jí)嵌套,即:條件集 可以 嵌套 條件集亚亲;
短路運(yùn)算
在對(duì)條件表達(dá)式進(jìn)行運(yùn)算的過(guò)程中彻采,如果運(yùn)算中途已經(jīng)能夠確認(rèn)最終的運(yùn)算結(jié)果腐缤,則便會(huì)停止對(duì)剩余表達(dá)式的計(jì)算,并返回計(jì)算結(jié)果肛响;-
簡(jiǎn)單優(yōu)先
為了提高運(yùn)算效率岭粤,除了加入了短路運(yùn)算的特性外,還加入了簡(jiǎn)單優(yōu)先的計(jì)算原則特笋,即:對(duì)于同一層級(jí)表達(dá)式剃浇,會(huì)按照下面的順序優(yōu)先計(jì)算:- BaseCondition | FunCondition: 除了 異步條件 PromCondition、條件集 ConditionSet 以外的所有其它數(shù)據(jù)類(lèi)型的條件表達(dá)式猎物,這些條件會(huì)被當(dāng)作布爾值來(lái)計(jì)算偿渡;
- ConditionSet : 條件集;
- PromCondition : 異步條件霸奕;
3. 安裝方式
目前溜宽,安裝方式有以下幾種:
方式1:通過(guò) npm 安裝
npm install --save condition-operat
方式2:直接下載原代碼
您可直接從 git倉(cāng)庫(kù) 下載代碼文件;
倉(cāng)庫(kù)里包含了 源碼 和 編譯后的代碼文件 :
- conditionOperat 的源碼文件是
src/conditionOperat
有 TypeScript 版本 和 JavaScript 版本质帅; - conditionOperat 的編譯后的文件是
dist/conditionOperat.js
适揉;
您可以直接把任一 源碼 或 編譯后 的文件拷貝到您的項(xiàng)目中去;然后使用如下代碼在您的項(xiàng)目中引入 conditionOperat
:
import { conditionOperat , create } from "path/to/package/conditionOperat";
或者
import conditionOperat from "path/to/package/conditionOperat";
方式3:通過(guò)<script>
標(biāo)簽引入
您可直接下載 git倉(cāng)庫(kù) 中的 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ì)的接口信息嫉嘀,請(qǐng)到 API接口文檔
4.1. 最簡(jiǎn)單的使用
// 求表達(dá)式 true 的值
conditionOperat(true); //結(jié)果: true
4.2. 與運(yùn)算
對(duì)于基本類(lèi)型的數(shù)據(jù)(如:boolean、number魄揉、string剪侮、symbol、undefined洛退、null )都會(huì)被作為布爾值來(lái)對(duì)待瓣俯,即會(huì)被簡(jiǎn)單的轉(zhuǎn)為布爾類(lèi)型;
// 對(duì)一組表達(dá)式做 與 運(yùn)算兵怯;
var condExpr = [
true,
false,
"字符串會(huì)作為布爾值對(duì)待",
34,
0, // 相當(dāng)于 false
];
conditionOperat(condExpr); //結(jié)果: false
或者
// 對(duì)一組表達(dá)式做 與 運(yùn)算
var condExpr = [
true,
false,
true
];
condExpr.rel = "and"; // rel 可設(shè)置為 "and" (與運(yùn)算) 或 "or"(或運(yùn)算)彩匕, 如果沒(méi)設(shè)置 rel ,則默認(rèn)會(huì)用 與運(yùn)算 "and"
conditionOperat(condExpr); //結(jié)果: false
4.3. 或運(yùn)算
// 對(duì)一組表達(dá)式做 或 運(yùn)算
var condExpr = [
true,
false,
true
];
condExpr.rel = "or"; //設(shè)置 數(shù)組中元素之間關(guān)系為 或 媒区; 即:對(duì)所有元素進(jìn)行 或運(yùn)算
conditionOperat(condExpr); //結(jié)果: true
4.4. 先或后非
var condExpr = [
true,
false,
true
];
condExpr.rel = "or"; //設(shè)置:數(shù)組中元素之間關(guān)系為 或 驼仪; 即:對(duì)所有元素進(jìn)行 或運(yùn)算
condExpr.not = true; //設(shè)置:對(duì)運(yùn)算結(jié)果 取反,即 對(duì)所有元素進(jìn)行 或運(yùn)算之后 再取反
conditionOperat(condExpr); //結(jié)果: false
4.5. 表達(dá)式可以嵌套
//里面的表達(dá)式
var innerExpr = [
false,
true
];
innerExpr.rel = "or";
var condExpr = [
true,
innerExpr, // 表達(dá)式可以嵌套表達(dá)式
true
];
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.6. 函數(shù)類(lèi)型的表達(dá)式
函數(shù)也可作為表達(dá)式袜漩,運(yùn)算時(shí)會(huì)將函數(shù)的返回值作新的表達(dá)式重新計(jì)算绪爸,如果函數(shù)返回的還是函數(shù),則會(huì)對(duì)該返回的函數(shù)繼續(xù)運(yùn)算宙攻;
函數(shù)也可以返回一個(gè) Promise奠货,針對(duì) Promise類(lèi)型表達(dá)式的運(yùn)算方式,詳見(jiàn)[Promise類(lèi)型的表達(dá)式][]
var condExpr = [
function(){return false}, //表達(dá)式可以是個(gè)返回 另一個(gè)表達(dá)式的函數(shù)
function(){return "返回其它類(lèi)型的值"},
function(){
return ()=>{return 5}
}, //函數(shù)表達(dá)式 可以返回 另一個(gè)函數(shù)表達(dá)式
true, //表達(dá)式的類(lèi)型可以混合使用
];
conditionOperat(condExpr); //結(jié)果: false
在執(zhí)行條件運(yùn)算 conditionOperat()
時(shí)粘优,你也可以設(shè)置函數(shù)條件在被調(diào)用時(shí)的 this 值 和 參數(shù)仇味,如下:
// 驗(yàn)證名字
function verifyName(phoneNum,gender){
var name = this.value;
return name.trim().length > 0
}
//驗(yàn)證手機(jī)號(hào)
function verifyPhone(phoneNum,gender){
return /\d{11}/.test(phoneNum)
}
// 驗(yàn)證性別
function verifyGender(phoneNum,gender){
return /^男|女$/.test(gender)
}
// 條件表達(dá)式:名字呻顽、手機(jī)號(hào)、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
// 獲取保存名字的輸入框的dom元素 來(lái)作為 函數(shù)條件的 this 的值丹墨;
var thisValue = document.getElementById("nameInput");
// 給函數(shù)條件傳遞兩個(gè)參數(shù):手機(jī)號(hào) 和 性別
var args = ["17639609033","男"];
// conditionOperat() 的第一個(gè)參數(shù)是 條件表達(dá)式廊遍,第二個(gè)參數(shù)是 函數(shù)條件的 this 值,第三個(gè)參數(shù)是 函數(shù)條件 的參數(shù)數(shù)組
conditionOperat(condExpr,thisValue,args);
注意:
thisValue 和 args 會(huì)被應(yīng)用到所有的 函數(shù)條件贩挣,包括那些 運(yùn)算過(guò)程 中產(chǎn)生的函數(shù)條件喉前,比如:函數(shù)條件返回的函數(shù)條件、異步條件決議時(shí)傳遞出的 函數(shù)條件
4.7. 異步表達(dá)式
Promise 也可以作為表達(dá)式王财,當(dāng) Promise 作為表達(dá)式時(shí)卵迂,會(huì)根據(jù) resolve 的值來(lái)進(jìn)行計(jì)算,如果 Promise 是被 reject 了绒净,則會(huì)被作為 假 false 來(lái)處理见咒;
Promise 決議的值也可以是其它復(fù)雜的條件表達(dá)式,如:函數(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 會(huì)被作為 假值 來(lái)對(duì)待
},3000)
}),
];
condExpr.rel = "or"; //設(shè)置各 Promise 之間是 或 的關(guān)系
conditionOperat(condExpr).then(function (res) {
console.log(res)
}); //3秒后輸出: false
4.8. 非運(yùn)算
對(duì)于任何對(duì)象(比如:普通對(duì)象、函數(shù)缤言、Promise宝当、數(shù)組 等等),都可以通過(guò)向其添加 not 屬性來(lái)設(shè)置 非運(yùn)算胆萧;設(shè)置非運(yùn)算后庆揩,會(huì)先對(duì) 該對(duì)象進(jìn)行求值,然后再對(duì)求得的值取反跌穗;
4.8.1. 普通對(duì)象的非運(yùn)算
/*
先對(duì)對(duì)象 求值订晌,然后再取反;
由于對(duì)象 轉(zhuǎn)成布爾后 為 true瞻离,對(duì) true 取反后 為 false 腾仅,所以 對(duì) 條件表達(dá)式 {not:true} 求值后 得 false
*/
var condExpr = {not:true};
conditionOperat(condExpr); //結(jié)果: false
4.8.2. 函數(shù)的非運(yùn)算
/*
先對(duì)函數(shù) 求值,然后再取反套利;
先對(duì)函數(shù) 求值,得 true鹤耍,再取反肉迫,得 false
*/
var condExpr = function(){
return true
};
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.8.3. 異步非運(yùn)算
/*
先對(duì) Promise 求值,然后再取反稿黄;
選對(duì) 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. 條件集的非運(yùn)算
/*
先運(yùn)算 數(shù)組中所有元素相或 的值,為 true,然后再取反箫津,得 false
*/
var condExpr = [
true,
0,
{}
];
condExpr.rel = "or"; //設(shè)置 或 關(guān)系
condExpr.not = true;
conditionOperat(condExpr); //結(jié)果: false
4.9. 異步表達(dá)式與其它類(lèi)型的表達(dá)式混合使用
Promise類(lèi)型的條件表達(dá)工也可以與其它類(lèi)型的條件表達(dá)式混合使用;
對(duì)于帶有 Promise 類(lèi)型的條件表達(dá)式蜕着,conditionOperat(condExpr) 返回的結(jié)果可能是 布爾值僵蛛,也可能是 Promise ;這取決于通過(guò) 非 Promise 的表達(dá)式是否能求出 condExpr 的值瑟幕,如果能磕蒲,則返回的是布爾值,如果不能只盹,則 condExpr 的值只能依賴(lài)于 其中的 Promise 表達(dá)式辣往,則 conditionOperat(condExpr) 就會(huì)返回一個(gè) Promise ;
如果 返回的是 Promise 殖卑,側(cè) Promise 決義后的值值便是表達(dá)式 condExpr 的運(yùn)算結(jié)果站削;
var condExpr = [
true, //布爾值作為條件,直接表示條件成立或失敗
false,
3.5, //數(shù)字會(huì)被轉(zhuǎn)為布爾類(lèi)型孵稽;
0, //0 相當(dāng)于 false
"字符串也可作為表達(dá)式", //字符串也會(huì)被轉(zhuǎn)為布爾類(lèi)型许起;
{}, //對(duì)象會(huì)被轉(zhuǎn)為布爾類(lèi)型;
//對(duì)于任何對(duì)象(比如:函數(shù)肛冶、Promise街氢、數(shù)組 等等),都可以通過(guò)向其添加 not 屬性來(lái)設(shè)置 非運(yùn)算睦袖;
{not:true}, //對(duì)象會(huì)被轉(zhuǎn)為 true珊肃,由于本身的 not 屬性為 true,所以馅笙,還會(huì)對(duì)該對(duì)象本盤(pán)的值 true 再進(jìn)行一次 非運(yùn)算伦乔,所以該表達(dá)式的值為 false
function () {return false}, //函數(shù)作為條件,會(huì)根據(jù)函數(shù)的返回值作為該條件的計(jì)算結(jié)果
function () {return [false,45]}, //函數(shù)也可以返回 條件集
[
"", // 空字符串相當(dāng)于 false
{mes:"對(duì)象也可作為表達(dá)式"}, //對(duì)象也可以作為條件董习,它會(huì)被當(dāng)作真值來(lái)對(duì)待烈和,即相當(dāng)于 true
new Promise(function (resolve, reject) {
setTimeout( ()=> {
resolve(true)
},500)
}), // Promise 作為表達(dá)式,當(dāng)被計(jì)算時(shí)皿淋,會(huì)根據(jù) Promise 被 resolve 時(shí)的 value 來(lái)作為 計(jì)算結(jié)果招刹;
new Promise(function (resolve, reject) {
var funCond = ()=>{return false};
setTimeout( ()=> {
resolve(funCond)
},500)
}) // Promise 作為表達(dá)式,當(dāng)被計(jì)算時(shí)窝趣,會(huì)根據(jù) Promise 被 resolve 時(shí)的 value 來(lái)作為 計(jì)算結(jié)果疯暑,如果 value 仍是復(fù)雜的表達(dá)式(比如:函數(shù)),還會(huì)繼續(xù)計(jì)算哑舒;
], // 條件集妇拯,也就是數(shù)組,也可以作為條件表達(dá)式洗鸵,會(huì)根據(jù) 該條件集的計(jì)算結(jié)果作為 該條件集 的結(jié)果
new Promise(function (resolve, reject) {
setTimeout( ()=> {
reject("reject會(huì)被認(rèn)為返回了假值")
},300)
}) // 如果 Promise 被 reject 了越锈,則 該 Promise 表達(dá)式的計(jì)算結(jié)果為 false
];
condExpr.rel = "or"; //設(shè)置條件集中所有條件表達(dá)式的關(guān)系為 或
condExpr.not = true; //對(duì) 條件集中所有表達(dá)式 進(jìn)行 或運(yùn)算(由rel屬性指定) 之后仗嗦,再對(duì)其結(jié)果取反,即:再進(jìn)行 非運(yùn)算甘凭;
/*
調(diào)用 conditionOperat 函數(shù)對(duì) 條件表達(dá)式 condExpr 進(jìn)行求值稀拐;
返回的結(jié)果可能是 布爾值,也可能是 Promise 对蒲;這取決于通過(guò) 非 Promise 的表達(dá)式是否能求出 condExpr 的值钩蚊,如果能,則返回的是布爾值蹈矮,如果不能砰逻,則 condExpr 的值只能依賴(lài)于 其中的 Promise 表達(dá)式,則 conditionOperat(condExpr) 就會(huì)返回一個(gè) Promise 泛鸟;
如果 返回的是 Promise 蝠咆,側(cè) Promise 決義后的值值便是表達(dá)式 condExpr 的運(yùn)算結(jié)果
*/
var res = conditionOperat(condExpr)
if (res instanceof Promise){
res.then((value)=>{
console.log("condExpr條件表達(dá)式的值是:",value);
})
}else {
console.log("condExpr條件表達(dá)式的值是:",res);
}
4.10. 快捷工具
條件運(yùn)算函數(shù) conditionOperat(condExpress:CondExpression,thisValue?:ThisValue, args?:Args):OperatedResult
可接收如下三個(gè)參數(shù)
- condExpress : CondExpression 條件表達(dá)式
- thisValue ?: any 設(shè)置條件表達(dá)式中 函數(shù)條件 的 this 的值
- args 北滥?: any[] 設(shè)置條件表達(dá)式中 函數(shù)條件 的 參數(shù)序列
這三個(gè)參數(shù)中刚操,只有 條件表達(dá)式 condExpress 是必須參數(shù);
有些時(shí)候再芋,我們可能經(jīng)常需要 對(duì)同一條件表達(dá)式 condExpress 進(jìn)行運(yùn)算菊霜,只是傳不同的 thisValue 或 args ;
比如:對(duì)表單中若干輸入框進(jìn)行驗(yàn)證济赎,這些輸入框的驗(yàn)證條件是一定的鉴逞,但每次提交表單時(shí),各個(gè)輸入框的值是不一樣的司训,對(duì)于這樣的場(chǎng)景构捡,我們每次進(jìn)行條件運(yùn)算時(shí),都要傳入同一 條件表達(dá)式 condExpress 和 包含各個(gè)輸入框值的 args conditionOperat(condExpress,null, args)
壳猜,如果 每次表單的dom的結(jié)構(gòu)都是一樣的勾徽,也可以將 表單的 dom 對(duì)象 作為 thisValue 參數(shù),讓 函數(shù)條件 自動(dòng)獲取對(duì)應(yīng)的輸入框的值并驗(yàn)證统扳,這樣喘帚,我們不用每次再分別取各個(gè)輸入框的值了,只需要給 conditionOperat()
傳 條件表達(dá)式 condExpress 和 thisValue 就行了咒钟,如 conditionOperat(condExpress,thisValue)
啥辨;
盡管這樣,每次條件運(yùn)算盯腌,還是需要傳入一樣的 條件表達(dá)式,這是重復(fù)的操作陨瘩;
為了解決這類(lèi)問(wèn)題腕够,我封裝了一個(gè)工具函數(shù) create()
级乍,它根據(jù)給定的參數(shù),來(lái)創(chuàng)建專(zhuān)門(mén)用來(lái)接收剩余參數(shù)的條件運(yùn)算函數(shù)帚湘;
有兩種方式可以訪(fǎng)問(wèn)到 create()
函數(shù):
- 直接導(dǎo)入create函數(shù)
import { create玫荣,conditionOperat } from "condition-operat"
; - 通過(guò) conditionOperat 的 create 方法來(lái)訪(fǎng)問(wèn):
conditionOperat.create(options)
;
create()
的使用示例如下:
// 驗(yàn)證名字
function verifyName(target){
return target.name.trim().length > 0
}
//驗(yàn)證手機(jī)號(hào)
function verifyPhone(target){
return /\d{11}/.test(target.phoneNum)
}
// 驗(yàn)證性別
function verifyGender(target){
return /^男|女$/.test(target.gender)
}
// 條件表達(dá)式:名字、手機(jī)號(hào)大诸、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
/**
* 創(chuàng)建條件表達(dá)式 condExpr 和 thisValue (值為 `null`) 的快捷函數(shù) operatWith 捅厂;
*
* 因?yàn)閯?chuàng)建 `operatWith()` 時(shí) 給 `create()` 傳了兩個(gè)選項(xiàng) expr 和 "this" ,還剩余一個(gè)選項(xiàng) args 參數(shù)沒(méi)有傳资柔,
* 所以 這個(gè) operatWith() 快捷函數(shù)只接收一個(gè)參數(shù)焙贷,即 args ;
*/
var operatWith = create({
expr:condExpr,
"this":null
});
// 被測(cè)試的目標(biāo)
var target = {
name:"郭斌勇",
gender:"男",
phoneNum:""
};
// 傳入 args
operatWith([target]); //結(jié)果:false
或者
// 驗(yàn)證名字
function verifyName(){
var inputDom = this.elements.name;
var name = inputDom.value;
return name.trim().length > 0
}
//驗(yàn)證手機(jī)號(hào)
function verifyPhone(){
var inputDom = this.elements.phoneNum;
var phoneNum = inputDom.value;
return /\d{11}/.test(phoneNum)
}
// 驗(yàn)證性別
function verifyGender(){
var inputDom = this.elements.gender;
var gender = inputDom.value;
return /^男|女$/.test(gender)
}
// 條件表達(dá)式:名字贿堰、手機(jī)號(hào)辙芍、性格慎必須都要符合要求
var condExpr = [verifyName,verifyPhone,verifyGender];
/**
* 創(chuàng)建條件表達(dá)式 condExpr 的快捷函數(shù) operatWith ;
*
* 因?yàn)閯?chuàng)建 `operatWith()` 時(shí) 給 `create()` 傳了一個(gè)選項(xiàng) expr 羹与,還剩余二個(gè)選項(xiàng) "this" 和 args 選項(xiàng)沒(méi)有傳故硅,
* 所以 這個(gè) operatWith() 快捷函數(shù)可以接收二個(gè)參數(shù),即 "this" 和 args 纵搁; 但本示例中的 函數(shù)條件 只用到了 "this" 選項(xiàng) 吃衅,沒(méi)有用到 args ,所以腾誉,在使用 operatWith() 時(shí)徘层,只需要給其傳一個(gè)參數(shù) thisValue 即可;
*/
var operatWith = create({expr:condExpr});
// 被測(cè)試的目標(biāo)
var thisValue = document.getElementById("form");
// 傳入 thisValue 參數(shù)
operatWith(thisValue);
其中妄辩,當(dāng)傳給 create() 的選項(xiàng)只包含 表達(dá)式 condExpr 時(shí)惑灵,可以直接將表達(dá)式 condExpr 作為參數(shù)傳給 create() ,如 create(condExpr)
有您的支持眼耀,我會(huì)在開(kāi)源的道路上英支,越走越遠(yuǎn) 贊賞碼