javascript 参数检验(一):完成一个轻易的参数检验东西

综述

javascript 属于弱范例言语,参数的范例毛病只能在运转期发明。当你须要 expose “非常硬朗”的接口给外部,或许在调试较大项目的时刻,你能够会思念强范例言语的范例束缚,或许 assert 一类东西。

正由于 js 没有范例束缚,也没有 assert 如许的“契约型”断言东西,所以一致个人写出的 js 代码,硬朗性经常是不稳固的,偶然束缚多,偶然束缚少,偶然刻返回 null,偶然刻抛非常,而且束缚代码也经常不一致放在函数入口处。

本文尝试编写一种参数搜检东西,期待能减缓相似问题。

参数搜检

假定,我们须要给一切接口一致增加稳固的束缚,以及束缚损坏后一致的反应行动(比方崩溃),除了言语原生支撑(据说 Eiffel 有这个才能,有兴致的能够 google 下),最直接的要领就是想象一个相似 assert 的参数搜检函数 check,在每一个函数入口处挪用 check 搜检参数,假如搜检失利则实行既定的失利反应。

假如一切的函数都如许编写,就能够保证一切函数严格实行束缚,束缚损坏后马上住手运转,并打印响应的信息。

接口

我们很轻易大抵想象一个 check 接口的样子容貌——

check.setCheckFailedCallback(function (e) {});

function test(a) {
    check(a).搜检1(前提1).搜检2(前提2)……
}

有几个细节须要讨论一下:

  • 上面的代码运用了链式挪用,链式挪用的必要性是很显然的——我们须要一种组合搜检步骤的体式格局。为了完成链式挪用,check 返回的是一个特别的包装对象 Checker

  • 当参数 a 经由过程一切搜检后,代码向下实行。假如有一个搜检没有经由过程,此时须要实行一个反应。由于外层代码能够存在 try 块,所以这里抛非常是不可靠的,或许说我们要想一个方法抛出一个“不可 catch”的非常。这里采纳的最简朴的方法,上层设置回调函数 checkFailedCallback,搜检失利后自行处理结果,同时抛出一个非常。

  • check(a) 这类写法,现实上是做不到的。js 里没有宏,所以没有方法接收一个变量同时拿到变量的称号。假如要打印出搜检失利的参数名,须要写成 check(a, 'a')。这类写法有点累坠,能够有更好的计划,我还在思索。

逻辑组合

适才说到链式挪用能够用来组合搜检步骤,然则只要一种组合体式格局显然是不可的。由于搜检步骤之间的关联能够有三种:与、或、非。我们要想方法运用一致的划定规矩把三种关联表达清晰。

详细就不诠释了,分享一下我的划定规矩:

链式挪用完成“与”

// a 是 number 型,而且大于 1 小于 3
check(a, 'a').is('number').gt(1).lt(3);

参数表完成“或”

// a 是 number 型,而且位于 [0, 1) || (1, 2] 区间上
check(a, 'a').is('number').within('[0, 1)', '(1, 2]');

注:由于参数表完成“或”,所以这里“或”的优先级永远比“与”高,假如须要“与”比“或”高,则须要一点技能,详细见我这篇文章

not 属性完成“非”

// a 是字符串而且不符合正则表达式 /^[\w][\w\d]+$/
check(a, 'a').is('string').not.match(/^[\w][\w\d]+$/);

// a 是字符串而且不符合正则表达式 /^[\w][\w\d]+$/, 而且长度即是 10
check(a, 'a').is('string').not.match(/^[\w][\w\d]+$/).length().eq(10);

注:

  1. not 是一个特别属性,会返回一个特别对象 NotChecker,这个对象运用 try 实行原对象的搜检要领,catch 到非常则以为搜检经由过程。而且 NotChecker 的搜检要领返回的是原对象而不是本身,所以 not.match 以后衔接 length 时,已不再 not 的作用局限。

  2. 由于德摩根定律的存在,not 后的参数表现实上在表达”与”的关联,比方:

    check(a, 'a').not.is('string', 'number').

    示意的是参数 a 既不为 string 也不为 number。

其他

别的,为了方便运用,还须要完成一些别的的接口,比方:

// a 包括属性 foo,大于 1 小于 3; 同时包括属性 bar, 大于 2 小于 4
check(a, 'a').has('foo').gt(1).lt(3).owner.has('bar').gt(2).lt(4);

注:

  1. 上面的代码中,has 是一个特别要领,它磨练参数中是不是包括指定的属性(own property),假如包括,就返回一个包装该属性的 Checker,不然抛搜检失利的非常。

  2. owner 是一个特别属性,它返回包装上一层对象的 Checker 对象。所以我们能够在挪用 has 搜检属性以后,挪用 owner“跳回去”继承搜检上层对象。

代码

为了磨练上面的主意,我完成了一个 js 库 param-check,代码位于:
https://github.com/yusangeng/param-check

由于只是一个言语切换是发生的 idea,所以现在这个库还不完美,现实能有多大意义还不好说,对机能和编程范式的影响还须要评价。

    原文作者:Y3G
    原文地址: https://segmentfault.com/a/1190000006024733
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞