摘要:本文嘗試編寫(xiě)一種參數(shù)檢查工具,期待能緩解類(lèi)似問(wèn)題。為了實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,返回的是一個(gè)特殊的包裝對(duì)象。如果要打印出檢查失敗的參數(shù)名,需要寫(xiě)成。由于德摩根定律的存在,后的參數(shù)表實(shí)際上在表達(dá)與的關(guān)系,比如表示的是參數(shù)既不為也不為。
綜述
javascript 屬于弱類(lèi)型語(yǔ)言,參數(shù)的類(lèi)型錯(cuò)誤只能在運(yùn)行期發(fā)現(xiàn)。當(dāng)你需要 expose “非常健壯”的接口給外部,或者在調(diào)試較大項(xiàng)目的時(shí)候,你可能會(huì)懷念強(qiáng)類(lèi)型語(yǔ)言的類(lèi)型約束,或者 assert 一類(lèi)東西。
正因?yàn)?js 沒(méi)有類(lèi)型約束,也沒(méi)有 assert 這樣的“契約型”斷言工具,所以同一個(gè)人寫(xiě)出的 js 代碼,健壯性常常是不穩(wěn)定的,有時(shí)約束多,有時(shí)約束少,有時(shí)候返回 null,有時(shí)候拋異常,并且約束代碼也常常不統(tǒng)一放在函數(shù)入口處。
本文嘗試編寫(xiě)一種參數(shù)檢查工具,期待能緩解類(lèi)似問(wèn)題。
參數(shù)檢查假設(shè),我們需要給所有接口統(tǒng)一添加穩(wěn)定的約束,以及約束破壞后統(tǒng)一的反饋行為(比如崩潰),除了語(yǔ)言原生支持(聽(tīng)說(shuō) Eiffel 有這個(gè)能力,有興趣的可以 google 下),最直接的方法就是設(shè)計(jì)一個(gè)類(lèi)似 assert 的參數(shù)檢查函數(shù) check,在每個(gè)函數(shù)入口處調(diào)用 check 檢查參數(shù),如果檢查失敗則執(zhí)行既定的失敗反饋。
如果所有的函數(shù)都這樣編寫(xiě),就可以保證所有函數(shù)嚴(yán)格執(zhí)行約束,約束破壞后立刻停止運(yùn)行,并打印相應(yīng)的信息。
接口我們很容易大致設(shè)想一個(gè) check 接口的模樣——
check.setCheckFailedCallback(function (e) {}); function test(a) { check(a).檢查1(條件1).檢查2(條件2)…… }
有幾個(gè)細(xì)節(jié)需要討論一下:
上面的代碼使用了鏈?zhǔn)秸{(diào)用,鏈?zhǔn)秸{(diào)用的必要性是很顯然的——我們需要一種組合檢查步驟的方式。為了實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,check 返回的是一個(gè)特殊的包裝對(duì)象 Checker。
當(dāng)參數(shù) a 通過(guò)所有檢查后,代碼向下執(zhí)行。如果有一個(gè)檢查沒(méi)有通過(guò),此時(shí)需要執(zhí)行一個(gè)反饋。由于外層代碼可能存在 try 塊,所以這里拋異常是不可靠的,或者說(shuō)我們要想一個(gè)辦法拋出一個(gè)“不可 catch”的異常。這里采用的最簡(jiǎn)單的辦法,上層設(shè)置回調(diào)函數(shù) checkFailedCallback,檢查失敗后自行處理結(jié)果,同時(shí)拋出一個(gè)異常。
check(a) 這種寫(xiě)法,實(shí)際上是做不到的。js 里沒(méi)有宏,所以沒(méi)有辦法接受一個(gè)變量同時(shí)拿到變量的名稱(chēng)。如果要打印出檢查失敗的參數(shù)名,需要寫(xiě)成 check(a, "a")。這種寫(xiě)法有點(diǎn)累贅,可能有更好的方案,我還在思考。
邏輯組合剛才說(shuō)到鏈?zhǔn)秸{(diào)用可以用來(lái)組合檢查步驟,但是只有一種組合方式顯然是不行的。因?yàn)闄z查步驟之間的關(guān)系可能有三種:與、或、非。我們要想辦法使用同一的規(guī)則把三種關(guān)系表達(dá)清楚。
具體就不解釋了,分享一下我的規(guī)則:
鏈?zhǔn)秸{(diào)用實(shí)現(xiàn)“與”:
// a 是 number 型,并且大于 1 小于 3 check(a, "a").is("number").gt(1).lt(3);
參數(shù)表實(shí)現(xiàn)“或”:
// a 是 number 型,并且位于 [0, 1) || (1, 2] 區(qū)間上 check(a, "a").is("number").within("[0, 1)", "(1, 2]");
注:由于參數(shù)表實(shí)現(xiàn)“或”,所以這里“或”的優(yōu)先級(jí)永遠(yuǎn)比“與”高,如果需要“與”比“或”高,則需要一點(diǎn)技巧,具體見(jiàn)我這篇文章。
not 屬性實(shí)現(xiàn)“非”:
// a 是字符串并且不符合正則表達(dá)式 /^[w][wd]+$/ check(a, "a").is("string").not.match(/^[w][wd]+$/); // a 是字符串并且不符合正則表達(dá)式 /^[w][wd]+$/, 并且長(zhǎng)度等于 10 check(a, "a").is("string").not.match(/^[w][wd]+$/).length().eq(10);
注:
not 是一個(gè)特殊屬性,會(huì)返回一個(gè)特殊對(duì)象 NotChecker,這個(gè)對(duì)象使用 try 執(zhí)行原對(duì)象的檢查方法,catch 到異常則認(rèn)為檢查通過(guò)。并且 NotChecker 的檢查方法返回的是原對(duì)象而不是自己,所以 not.match 之后連接 length 時(shí),已經(jīng)不再 not 的作用范圍。
由于德摩根定律的存在,not 后的參數(shù)表實(shí)際上在表達(dá)"與"的關(guān)系,比如:
check(a, "a").not.is("string", "number").
表示的是參數(shù) a 既不為 string 也不為 number。
其他另外,為了方便使用,還需要實(shí)現(xiàn)一些另外的接口,比如:
// a 包含屬性 foo,大于 1 小于 3; 同時(shí)包含屬性 bar, 大于 2 小于 4 check(a, "a").has("foo").gt(1).lt(3).owner.has("bar").gt(2).lt(4);
注:
上面的代碼中,has 是一個(gè)特殊方法,它檢驗(yàn)參數(shù)中是否包含指定的屬性(own property),如果包含,就返回一個(gè)包裝該屬性的 Checker,否則拋檢查失敗的異常。
owner 是一個(gè)特殊屬性,它返回包裝上一層對(duì)象的 Checker 對(duì)象。所以我們可以在調(diào)用 has 檢查屬性之后,調(diào)用 owner“跳回去”繼續(xù)檢查上層對(duì)象。
代碼為了檢驗(yàn)上面的想法,我實(shí)現(xiàn)了一個(gè) js 庫(kù) param-check,代碼位于:
https://github.com/yusangeng/param-check
因?yàn)橹皇且粋€(gè)語(yǔ)言切換是產(chǎn)生的 idea,所以目前這個(gè)庫(kù)還不完善,實(shí)際能有多大意義還不好說(shuō),對(duì)性能和編程范式的影響還需要評(píng)估。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/87798.html
摘要:上一個(gè)版本的問(wèn)題接這篇文章,聊聊參數(shù)檢查工具的完善。最終實(shí)現(xiàn)了這樣的效果檢查是否在區(qū)間與的交集內(nèi)檢查是否在區(qū)間與的并集內(nèi)檢查是否是數(shù)組并且長(zhǎng)度大于檢查是否不是之間的偶數(shù)即 上一個(gè)版本的問(wèn)題 接這篇文章,聊聊參數(shù)檢查工具 param-check 的完善。 按照之前的接口設(shè)計(jì),鏈?zhǔn)秸{(diào)用表示與,參數(shù)表表示或,自然產(chǎn)生了一個(gè)問(wèn)題——如果我要表達(dá)(A與B)或(C與D)這樣的邏輯組合應(yīng)該怎么辦? ...
摘要:介紹這是一篇短文,旨在展示多種在中安全地訪問(wèn)深層嵌套值的方式。所以每次我們想要訪問(wèn)深度嵌套的數(shù)據(jù)時(shí),都必須明確地進(jìn)行手動(dòng)檢查。我們還觸及了,可以更新深度嵌套數(shù)據(jù)而不會(huì)改變對(duì)象。 介紹 這是一篇短文,旨在展示多種在javascript中安全地訪問(wèn)深層嵌套值的方式。下面的例子通過(guò)不同的方式來(lái)解決這一問(wèn)題。 開(kāi)始之前,讓我們看下實(shí)際遇到這種狀況時(shí).. 假設(shè)有一個(gè)props對(duì)象(如下),當(dāng)我們...
摘要:檢驗(yàn)是用來(lái)檢驗(yàn)序列是否平穩(wěn)的方式一般來(lái)說(shuō)是時(shí)間序列中的一種檢驗(yàn)方法中可使用現(xiàn)成的工具來(lái)實(shí)現(xiàn)檢驗(yàn)最參數(shù)和返回結(jié)果的理解還不夠深刻后頭再把參數(shù)和返回結(jié)果都加上參數(shù)項(xiàng)序列,一維數(shù)組差分次數(shù)只有常量,有常量項(xiàng)和趨勢(shì)項(xiàng),有常量項(xiàng)線性和二次趨勢(shì) adf檢驗(yàn)是用來(lái)檢驗(yàn)序列是否平穩(wěn)的方式一般來(lái)說(shuō)是時(shí)間序列中的一種檢驗(yàn)方法python中可使用現(xiàn)成的工具statsmodels來(lái)實(shí)現(xiàn)adf檢驗(yàn) import...
閱讀 4078·2021-11-22 13:53
閱讀 1776·2021-09-23 11:52
閱讀 2537·2021-09-06 15:02
閱讀 1095·2019-08-30 15:54
閱讀 957·2019-08-30 14:15
閱讀 2439·2019-08-29 18:39
閱讀 762·2019-08-29 16:07
閱讀 555·2019-08-29 13:13