強烈推薦!條件運算工具:condition-operat 可對同步、異步條件進行復(fù)雜的邏輯運算

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)先計算:

    1. BaseCondition | FunCondition: 除了 異步條件 PromCondition、條件集 ConditionSet 以外的所有其它數(shù)據(jù)類型的條件表達式,這些條件會被當(dāng)作布爾值來計算;
    2. ConditionSet : 條件集;
    3. 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ù):

  1. 直接導(dǎo)入create函數(shù) import { create,conditionOperat } from "condition-operat";
  2. 通過 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) 贊賞碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容