电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

守護 Javascript 中的函數參數

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

作為開發者,我們花費許多時間來調試,尤其是在發現問題來源方面。開發工具指導我們追蹤調用棧,但是追蹤過程仍然相當耗時,尤其在遇到級聯異步調用的時候。這一問題在很早以前就被發現了。

假設我們有一個從不同文檔結構中搜索包含指定字符串的元素的函數。我們使用以下看起來合法的調用:

grep( 'substring', tree );

但是我們并沒有得到期望的結果。按照以往的經驗,我們會花費一些時間來檢查給定的樹形文檔結構,時間有可能會很長。然后我們很可能會做其他的檢查,但是在最終,我們會從函數代碼中發現傳入的參數順序反了。這樣看來的話,我們只要關注函數的參數,就不會發生上面的錯誤。

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

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

但是,Javascript目前為止還沒有其他語言那樣內置的功能作為函數入口和結束處的驗證。對于一個示例,PHP語言有類型提示:

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

TypeScript 有嚴格類型:

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

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

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

根據在ES規范中提出來得特性,今后會有一個叫做 Guards 的功能,它建議使用下面的語法:

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

目前為止在Javascript中,我們必須使用外部庫或者可轉換的編譯器來解決這一問題。但是,可用的資源較少。最老的庫是 Cerny.js 。它類似于DbC(數據庫計算機),強大且靈活:

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'); });})();

但是對我而言,它讀起來很復雜。我更喜歡使用簡潔干凈的方式校驗前提條件/后置條件即可。Contractual 提供的語法很符合我的要求:

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之外,看起來都很不錯。如果你需要使用的話,必須用 Contractual或者 Babel Contracts 把源代碼編譯成Javascript。我不反對跨語言編譯器,但是如果讓我選擇的話,我寧愿用 TypeScript。

但是回到Javascript,不知道你有沒有發現,除了相關庫和框架外,我們在注釋函數和類的時候一直在用 JSDoc 描述函數入口和返回處的格式對比。如果文檔注釋可以用來驗證格式的話就太好了。正如你所理解的,它離不開編譯器。但是,我們可以使用依賴于Jascript文檔表達式的庫。幸運的是, byContract 就是這樣的庫。 byContract 的語法看起來像這樣:

/** * @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

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

byContract( value, 'JSDOC-EXPRESSION' );

或者值列表對應文檔表達式列表作為一對參數也可以:

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

byContract 會檢測傳入的值 ,如果和對應的 JSDoc 表達式格式不一致,就會拋出 帶有像 ` 傳入的值違反類型NaN`信息的 byContract.Exception 異常 。

在最簡單的案例中,byContract用來驗證如 `array`, `string`, `undefined`, `boolean`, `function`, `nan`, `null`, `number`, `object`, `regexp`之類的 原型類型:

byContract( true, 'boolean' );

當我們需要允許輸入值在一個指定類型列表中的時候,可以使用 type union 。

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

一個函數可以有必填的參數,也可以有可選參數。默認情況下,參數在和原型類型做對比的時候是必填的。但是用’=’修飾符我們就可以設置成可選類型。所以 byContract 處理如 `number=` 這樣的表達式時候,會轉為 `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.

當然,我們可以用接口來做比較。這樣我們就可以引用作用域范圍內任何可用的對象,包括Javascript內置接口:

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

對于數組和對象,我們可以有選擇性地驗證其內容。比如可以驗證所有數組的值必須是數字或者所有的對象的鍵和值是字符串類型:

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

以上的驗證對線性數據結構有用,其他情況下就不起作用了。所以同樣的,我們可以創建一個 type definition (類型定義)來描述對象的內容(參考byContract類型定義)然后在后面作為一個類型引用它即可。

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

這個示例定義了一個’Hero’類型來表示一個對象/命名空間,必須有boolean類型的 `hasSuperhumanStrength`和`hasWaterbreathing` 屬性。

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

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!

事實上,你很可能不要用事件來寫驗證函數,而是用外部庫(類似 validator )代替:

byContract.is.email = validator.isEmail;

驗證邏輯取決于開發環境。使用 byContract, 我們可以用全局觸發器來禁用驗證邏輯 :

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

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

來自:https://www.oschina.net/translate/guarding-functions-in-javascript

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 罐体电伴热工程-消防管道电伴热带厂家-山东沃安电气 | PAS糖原染色-CBA流式多因子-明胶酶谱MMP-上海研谨生物科技有限公司 | 钢格板|镀锌钢格板|热镀锌钢格板|格栅板|钢格板|钢格栅板|热浸锌钢格板|平台钢格板|镀锌钢格栅板|热镀锌钢格栅板|平台钢格栅板|不锈钢钢格栅板 - 专业钢格板厂家 | 上海道勤塑化有限公司 | 电动液压篮球架_圆管地埋式篮球架_移动平箱篮球架-强森体育 | 亳州网络公司 - 亳州网站制作 - 亳州网站建设 - 亳州易天科技 | 不锈钢闸阀_球阀_蝶阀_止回阀_调节阀_截止阀-可拉伐阀门(上海)有限公司 | 桥架-槽式电缆桥架-镀锌桥架-托盘式桥架 - 上海亮族电缆桥架制造有限公司 | 药品冷藏箱厂家_低温冰箱_洁净工作台-济南欧莱博电子商务有限公司官网 | 螺旋丝杆升降机-SWL蜗轮-滚珠丝杆升降机厂家-山东明泰传动机械有限公司 | CCC验厂-家用电器|服务器CCC认证咨询-奥测世纪 | 四探针电阻率测试仪-振实密度仪-粉末流动性测定仪-宁波瑞柯微智能 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | 箱式破碎机_移动方箱式破碎机/价格/厂家_【华盛铭重工】 | 合肥废气治理设备_安徽除尘设备_工业废气处理设备厂家-盈凯环保 合肥防火门窗/隔断_合肥防火卷帘门厂家_安徽耐火窗_良万消防设备有限公司 | 智慧旅游_智慧景区_微景通-智慧旅游景区解决方案提供商 | 螺钉式热电偶_便携式温度传感器_压簧式热电偶|无锡联泰仪表有限公司|首页 | 红立方品牌应急包/急救包加盟,小成本好项目代理_应急/消防/户外用品加盟_应急好项目加盟_新奇特项目招商 - 中红方宁(北京) 供应链有限公司 | 卓能JOINTLEAN端子连接器厂家-专业提供PCB接线端子|轨道式端子|重载连接器|欧式连接器等电气连接产品和服务 | 便携式谷丙转氨酶检测仪|华图生物科技百科| 工业PH计|工业ph酸度计|在线PH计价格-合肥卓尔仪器仪表有限公司 济南画室培训-美术高考培训-山东艺霖艺术培训画室 | 工业胀紧套_万向节联轴器_链条-规格齐全-型号选购-非标订做-厂家批发价格-上海乙谛精密机械有限公司 | 苹果售后维修点查询,苹果iPhone授权售后维修服务中心 – 修果网 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 | 代办建筑资质升级-建筑资质延期就找上海国信启航 | 大行程影像测量仪-探针型影像测量仪-增强型影像测量仪|首丰百科 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 27PR跨境电商导航 | 专注外贸跨境电商 | 氨水-液氨-工业氨水-氨水生产厂家-辽宁顺程化工 | 皮带输送机-大倾角皮带输送机-皮带输送机厂家-河南坤威机械 | 废旧物资回收公司_广州废旧设备回收_报废设备物资回收-益美工厂设备回收公司 | 沈阳缠绕包装机厂家直销-沈阳海鹞托盘缠绕包装机价格 | 山东风淋室_201/304不锈钢风淋室净化设备厂家-盛之源风淋室厂家 翻斗式矿车|固定式矿车|曲轨侧卸式矿车|梭式矿车|矿车配件-山东卓力矿车生产厂家 | 氨水-液氨-工业氨水-氨水生产厂家-辽宁顺程化工 | 飞飞影视_热门电影在线观看_影视大全| 企典软件一站式企业管理平台,可私有、本地化部署!在线CRM客户关系管理系统|移动办公OA管理系统|HR人事管理系统|人力 | 低合金板|安阳低合金板|河南低合金板|高强度板|桥梁板_安阳润兴 北京租车牌|京牌指标租赁|小客车指标出租 | 宁夏活性炭_防护活性炭_催化剂载体炭-宁夏恒辉活性炭有限公司 | 生产加气砖设备厂家很多,杜甫机械加气砖设备价格公道 | 广东青藤环境科技有限公司-水质检测| 碳化硅,氮化硅,冰晶石,绢云母,氟化铝,白刚玉,棕刚玉,石墨,铝粉,铁粉,金属硅粉,金属铝粉,氧化铝粉,硅微粉,蓝晶石,红柱石,莫来石,粉煤灰,三聚磷酸钠,六偏磷酸钠,硫酸镁-皓泉新材料 | 三效蒸发器_多效蒸发器价格_四效三效蒸发器厂家-青岛康景辉 | 隔爆型防爆端子分线箱_防爆空气开关箱|依客思 |