亚洲免费在线视频-亚洲啊v-久久免费精品视频-国产精品va-看片地址-成人在线视频网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

守護(hù) Javascript 中的函數(shù)參數(shù)

瀏覽:9日期:2023-11-16 16:44:50

作為開發(fā)者,我們花費(fèi)許多時(shí)間來(lái)調(diào)試,尤其是在發(fā)現(xiàn)問(wèn)題來(lái)源方面。開發(fā)工具指導(dǎo)我們追蹤調(diào)用棧,但是追蹤過(guò)程仍然相當(dāng)耗時(shí),尤其在遇到級(jí)聯(lián)異步調(diào)用的時(shí)候。這一問(wèn)題在很早以前就被發(fā)現(xiàn)了。

假設(shè)我們有一個(gè)從不同文檔結(jié)構(gòu)中搜索包含指定字符串的元素的函數(shù)。我們使用以下看起來(lái)合法的調(diào)用:

grep( 'substring', tree );

但是我們并沒有得到期望的結(jié)果。按照以往的經(jīng)驗(yàn),我們會(huì)花費(fèi)一些時(shí)間來(lái)檢查給定的樹形文檔結(jié)構(gòu),時(shí)間有可能會(huì)很長(zhǎng)。然后我們很可能會(huì)做其他的檢查,但是在最終,我們會(huì)從函數(shù)代碼中發(fā)現(xiàn)傳入的參數(shù)順序反了。這樣看來(lái)的話,我們只要關(guān)注函數(shù)的參數(shù),就不會(huì)發(fā)生上面的錯(cuò)誤。

function grep( tree, substring ){ if ( !( tree instanceof Tree ) ) { throw TypeError( 'Invalid tree parameter' ); } if ( typeof substring !== 'string' ) { throw TypeError( 'Invalid substring parameter' ); } //... }

這種驗(yàn)證方式是 Design by Contract approach 的一部分。它在軟件組成部分中列出了需要驗(yàn)證的前置條件和后置條件。在以上示例中,我們必須測(cè)試函數(shù)輸入?yún)?shù)符合指定的格式(比較第一個(gè)參數(shù)符合樹文檔的類型,第二個(gè)參數(shù)符合字符串類型)同時(shí)我們建議檢查函數(shù)輸出類型是否是一個(gè)字符串。

但是,Javascript目前為止還沒有其他語(yǔ)言那樣內(nèi)置的功能作為函數(shù)入口和結(jié)束處的驗(yàn)證。對(duì)于一個(gè)示例,PHP語(yǔ)言有類型提示:

<?php function grep( Tree $tree, string $substring ): string {}

TypeScript 有嚴(yán)格類型:

function grep( tree: Tree, substring: string ): string {}

此外,它還支持高級(jí)類型(聯(lián)合類型,可選類型,交叉類型,泛型等等):

function normalize( numberLike: number | string, modifier?: boolean ): string {}

根據(jù)在ES規(guī)范中提出來(lái)得特性,今后會(huì)有一個(gè)叫做 Guards 的功能,它建議使用下面的語(yǔ)法:

function grep( tree:: Tree, substring:: String ):: String {}

目前為止在Javascript中,我們必須使用外部庫(kù)或者可轉(zhuǎn)換的編譯器來(lái)解決這一問(wèn)題。但是,可用的資源較少。最老的庫(kù)是 Cerny.js 。它類似于DbC(數(shù)據(jù)庫(kù)計(jì)算機(jī)),強(qiáng)大且靈活:

var NewMath = {};(function() { var check = CERNY.check; var pre = CERNY.pre; var method = CERNY.method; // The new division function divide(a,b) { return a / b; } method(NewMath, 'divide', divide); // The precondition for a division pre(divide, function(a,b) { check(b !== 0, 'b may not be 0'); });})();

但是對(duì)我而言,它讀起來(lái)很復(fù)雜。我更喜歡使用簡(jiǎn)潔干凈的方式校驗(yàn)前提條件/后置條件即可。Contractual 提供的語(yǔ)法很符合我的要求:

function divide ( a, b ) { pre: typeof a === 'number'; typeof b === 'number'; b !== 0, 'May not divide by zero'; main: return a / b; post: __result < a;}alert(divide(10, 0));

除了不是Javascript之外,看起來(lái)都很不錯(cuò)。如果你需要使用的話,必須用 Contractual或者 Babel Contracts 把源代碼編譯成Javascript。我不反對(duì)跨語(yǔ)言編譯器,但是如果讓我選擇的話,我寧愿用 TypeScript。

但是回到Javascript,不知道你有沒有發(fā)現(xiàn),除了相關(guān)庫(kù)和框架外,我們?cè)谧⑨尯瘮?shù)和類的時(shí)候一直在用 JSDoc 描述函數(shù)入口和返回處的格式對(duì)比。如果文檔注釋可以用來(lái)驗(yàn)證格式的話就太好了。正如你所理解的,它離不開編譯器。但是,我們可以使用依賴于Jascript文檔表達(dá)式的庫(kù)。幸運(yùn)的是, byContract 就是這樣的庫(kù)。 byContract 的語(yǔ)法看起來(lái)像這樣:

/** * @param {number|string} sum * @param {Object.<string, string>} dictionary * @param {function} transformer * @returns {HTMLElement} */ function makeTotalElement( sum, dictionary, transformer ) { // Test if the contract is respected at entry point byContract( arguments, [ 'number|string', 'Object.<string, string>', 'function' ] ); // .. var res = document.createElement( 'div' ); // .. // Test if the contract is respected at exit point return byContract( res, 'HTMLElement' );} // Test it var el1 = makeTotalElement( 100, { foo: 'foo' }, function(){}); // ok var el2 = makeTotalElement( 100, { foo: 100 }, function(){}); // exception

如你所見,我們可以從文檔注釋處復(fù)制/粘貼指定的類型到 byContract 然后進(jìn)行對(duì)比,就這么簡(jiǎn)單。下面我們更仔細(xì)地檢查以下 。 byContract 可以被當(dāng)做UMD模塊(AMD或者CommonJS)或者全局變量來(lái)訪問(wèn)。我們可以把值 /Javascript 文檔表達(dá)式作為一對(duì)參數(shù)傳給 byContract

byContract( value, 'JSDOC-EXPRESSION' );

或者值列表對(duì)應(yīng)文檔表達(dá)式列表作為一對(duì)參數(shù)也可以:

byContract( [ value, value ], [ 'JSDOC-EXPRESSION', 'JSDOC-EXPRESSION' ] );

byContract 會(huì)檢測(cè)傳入的值 ,如果和對(duì)應(yīng)的 JSDoc 表達(dá)式格式不一致,就會(huì)拋出 帶有像 ` 傳入的值違反類型NaN`信息的 byContract.Exception 異常 。

在最簡(jiǎn)單的案例中,byContract用來(lái)驗(yàn)證如 `array`, `string`, `undefined`, `boolean`, `function`, `nan`, `null`, `number`, `object`, `regexp`之類的 原型類型:

byContract( true, 'boolean' );

當(dāng)我們需要允許輸入值在一個(gè)指定類型列表中的時(shí)候,可以使用 type union 。

byContract( 100, 'string|number|boolean' );

一個(gè)函數(shù)可以有必填的參數(shù),也可以有可選參數(shù)。默認(rèn)情況下,參數(shù)在和原型類型做對(duì)比的時(shí)候是必填的。但是用’=’修飾符我們就可以設(shè)置成可選類型。所以 byContract 處理如 `number=` 這樣的表達(dá)式時(shí)候,會(huì)轉(zhuǎn)為 `number|undefined`

function foo( bar, baz ) { byContract( arguments, [ 'number=', 'string=' ] );}

下面是Js文檔中 nullable/non-nullable types (可空/不可空類型):

byContract( 42, '?number' ); // a number or null. byContract( 42, '!number' ); // a number, but never null.

當(dāng)然,我們可以用接口來(lái)做比較。這樣我們就可以引用作用域范圍內(nèi)任何可用的對(duì)象,包括Javascript內(nèi)置接口:

var instance = new Date();byContract( instance, 'Date' );byContract( view, 'Backbone.NativeView' );byContract( e, 'Event' );

對(duì)于數(shù)組和對(duì)象,我們可以有選擇性地驗(yàn)證其內(nèi)容。比如可以驗(yàn)證所有數(shù)組的值必須是數(shù)字或者所有的對(duì)象的鍵和值是字符串類型:

byContract( [ 1, 1 ], 'Array.<number>' );byContract( { foo: 'foo', bar: 'bar' }, 'Object.<string, string>' );

以上的驗(yàn)證對(duì)線性數(shù)據(jù)結(jié)構(gòu)有用,其他情況下就不起作用了。所以同樣的,我們可以創(chuàng)建一個(gè) type definition (類型定義)來(lái)描述對(duì)象的內(nèi)容(參考byContract類型定義)然后在后面作為一個(gè)類型引用它即可。

byContract.typedef( 'Hero', { hasSuperhumanStrength: 'boolean', hasWaterbreathing: 'boolean' }); var superman = { hasSuperhumanStrength: true, hasWaterbreathing: false };byContract( superman, 'Hero' );

這個(gè)示例定義了一個(gè)’Hero’類型來(lái)表示一個(gè)對(duì)象/命名空間,必須有boolean類型的 `hasSuperhumanStrength`和`hasWaterbreathing` 屬性。

所有的方法都通過(guò)類型驗(yàn)證傳入的值,但是不變的量(常量)呢?我們可以用一個(gè)自定義類型來(lái)包裝類型約束。比如說(shuō)檢測(cè)字符串是不是一個(gè)郵件地址類型,我們可以增加這樣的驗(yàn)證:

byContract.is.email = function( val ){ var re = /^(([^<>()[].,;:s@']+(.[^<>()[].,;:s@']+)*)|('.+'))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/; return re.test( val );}byContract( 'john.snow@got.com', 'email' ); // ok byContract( 'bla-bla', 'email' ); // Exception!

事實(shí)上,你很可能不要用事件來(lái)寫驗(yàn)證函數(shù),而是用外部庫(kù)(類似 validator )代替:

byContract.is.email = validator.isEmail;

驗(yàn)證邏輯取決于開發(fā)環(huán)境。使用 byContract, 我們可以用全局觸發(fā)器來(lái)禁用驗(yàn)證邏輯 :

if ( env !== 'dev' ) { byContract.isEnabled = false;}

byContract 是一個(gè)很小的驗(yàn)證插件(壓縮文件大約1KB大?。?,你可以在你的Javascript代碼中使用它從而得到對(duì)比編程設(shè)計(jì)模式的好處。

來(lái)自:https://www.oschina.net/translate/guarding-functions-in-javascript

標(biāo)簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 亚洲精品国产三级在线观看 | 天堂视频免费看 | m男亚洲一区中文字幕 | 99精品一区二区免费视频 | 免费看一级做a爰片久久 | www.亚洲国产 | 国产亚洲一区二区三区 | 欧美一级鲁丝片 | 牛人盗摄一区二区三区视频 | 九月婷婷亚洲综合在线 | 黄色毛片播放 | 国产乱纶 | 免费观看亚洲视频 | 日韩欧美国产另类 | 日韩中文字幕在线免费观看 | 亚洲一区二区三区四区五区六区 | 久草社区视频 | 国产精品女在线观看 | 久久久久久久免费 | 免费亚洲视频 | 特级毛片全部免费播放器 | 男人的天堂在线免费视频 | 欧美性色黄大片一级毛片视频 | 男人在线网址 | 国产三级小视频在线观看 | 欧美成人www在线观看网页 | 国产欧美一区二区三区沐欲 | 久久99国产精品一区二区 | 成人a免费α片在线视频网站 | 国产自在自线午夜精品 | 99久久成人国产精品免费 | 久久99精品久久久久久久不卡 | av中文字幕网免费观看 | 国产欧美精品区一区二区三区 | 2022国产精品自拍 | 欧美13一14sexvideo欧 | 亚洲精品欧洲久久婷婷99 | 国产精品无码久久久久 | 福利片成人午夜在线 | v片在线播放 | 波多野结衣免费观看视频 |