前端技术
JavaScript API 设计原则详解
admin2019-12-23 16:02
2623人已围观
简介前段时间组织优化我们的原生模块 API(iOS、Android 模块封装成 JavaScript 接口),于是学习了几篇 JavaScript API 设计的文
前段时间组织优化我们的原生模块 API(iOS、Android 模块封装成 JavaScript 接口),于是学习了几篇 JavaScript API 设计的文章,尽管是旧文,但受益匪浅,这里记录一下。
好的 API 设计:在自描述的同时,达到抽象的目标。
设计良好的 API ,开发者可以快速上手,没必要经常抱着手册和文档,也没必要频繁光顾技术支持社区。
流畅的接口
方法链:流畅易读,更易理解。
//常见的 API 调用方式:改变一些颜色,添加事件监听var elem = document.getElementById("foobar");elem.style.background = "red";elem.style.color = "green";elem.addEventListener('click', function(event) { alert("hello world!");}, true);//(设想的)方法链 APIDOMHelper.getElementById('foobar') .setStyle("background", "red") .setStyle("color", "green") .addEvent("click", function(event) { alert("hello world"); });
设置和获取操作,可以合二为一;方法越多,文档可能越难写。
var $elem = jQuery("#foobar");//setter$elem.setCss("background", "green");//getter$elem.getCss("color") === "red";//getter, setter 合二为一$elem.css("background", "green");$elem.css("color") === "red";
一致性
相关的接口保持一致的风格,一整套 API 如果传递一种熟悉和舒适的感觉,会大大减轻开发者对新工具的适应性。
命名这点事:既要短,又要自描述,最重要的是保持一致性。
“There are only two hard problems in computer science: cache-invalidation and naming things.”“在计算机科学界只有两件头疼的事:缓存失效和命名问题”— Phil Karlton
选择一个你喜欢的措辞,然后持续使用。选择一种风格,然后保持这种风格。
处理参数
需要考虑大家如何使用你提供的方法,是否会重复调用?为何会重复调用?
你的 API 如何帮助开发者减少重复的调用?接收map映射参数,回调或者序列化的属性名,不仅让你的 API 更干净,而且使用起来更舒服、高效。
jQuery 的 css()
方法可以给 DOM 元素设置样式:
jQuery("#some-selector") .css("background", "red") .css("color", "white") .css("font-weight", "bold") .css("padding", 10);
这个方法可以接受一个 JSON 对象:
jQuery("#some-selector").css({ "background" : "red", "color" : "white", "font-weight" : "bold", "padding" : 10});//通过传一个 map 映射绑定事件jQuery("#some-selector").on({ "click" : myClickHandler, "keyup" : myKeyupHandler, "change" : myChangeHandler});//为多个事件绑定同一个处理函数jQuery("#some-selector").on("click keyup change", myEventHandler);
处理类型
定义方法的时候,需要决定它可以接收什么样的参数。我们不清楚人们如何使用我们的代码,但可以更有远见,考虑支持哪些参数类型。
//原来的代码DateInterval.prototype.days = function(start, end) { return Math.floor((end - start) / 86400000);};//修改后的代码DateInterval.prototype.days = function(start, end) { if (!(start instanceof Date)) { start = new Date(start); } if (!(end instanceof Date)) { end = new Date(end); } return Math.floor((end.getTime() - start.getTime()) / 86400000);};
加了短短的6行代码,我们的方法强大到可以接收Date
对象,数字的时间戳,甚至像Sat Sep 08 2012 15:34:35 GMT+0200 (CEST)
这样的字符串。
如果你需要确保传入的参数类型(字符串,数字,布尔),可以这样转换:
function castaway(some_string, some_integer, some_boolean) { some_string += ""; some_integer += 0; // parseInt(some_integer, 10) 更安全些 some_boolean = !!some_boolean;}
处理 undefined
为了使你的 API 更健壮,需要鉴别是否真正的undefined
值被传递进来,可以检查arguments
对象:
function testUndefined(expecting, someArgument) { if (someArgument === undefined) { console.log("someArgument 是 undefined"); } if (arguments.length > 1) { console.log("然而它实际是传进来的"); }}testUndefined("foo");// 结果: someArgument 是 undefinedtestUndefined("foo", undefined);// 结果: someArgument 是 undefined , 然而它实际是传进来的
给参数命名
event.initMouseEvent( "click", true, true, window, 123, 101, 202, 101, 202, true, false, false, false, 1, null);
Event.initMouseEvent 这个方法简直丧心病狂,不看文档的话,谁能说出每个参数是什么意思?
给每个参数起个名字,赋个默认值,可好:
event.initMouseEvent( type="click", canBubble=true, cancelable=true, view=window, detail=123, screenX=101, screenY=202, clientX=101, clientY=202, ctrlKey=true, altKey=false, shiftKey=false, metaKey=false, button=1, relatedTarget=null);
ES6, 或者 Harmony 就有 默认参数值 和 rest 参数 了。
参数接收 JSON 对象
与其接收一堆参数,不如接收一个 JSON 对象:
function nightmare(accepts, async, beforeSend, cache, complete, /* 等28个参数 */) { if (accepts === "text") { // 准备接收纯文本 }}function dream(options) { options = options || {}; if (options.accepts === "text") { // 准备接收纯文本 }}
调用起来也更简单了:
nightmare("text", true, undefined, false, undefined, /* 等28个参数 */);dream({ accepts: "text", async: true, cache: false});
参数默认值
参数最好有默认值,通过 [jQuery.extend()](http://api.jquery.com/jQuery.extend/%20%20,%20_.extend() http://underscorejs.org/#extend) 和 Protoype 的 Object.extend ,可以覆盖预设的默认值。
var default_options = { accepts: "text", async: true, beforeSend: null, cache: false, complete: null, // …};function dream(options) { var o = jQuery.extend({}, default_options, options || {}); console.log(o.accepts);}dream({ async: false });// prints: "text"
扩展性
回调(callbacks)
通过回调, API 用户可以覆盖你的某一部分代码。把一些需要自定义的功能开放成可配置的回调函数,允许 API 用户轻松覆盖你的默认代码。
API 接口一旦接收回调,确保在文档中加以说明,并提供代码示例。
事件(events)
事件接口最好见名知意,可以自由选择事件名字,避免与原生事件重名。
处理错误
不是所有的错误都对开发者调试代码有用:
// jQuery 允许这么写$(document.body).on('click', {});// 点击时报错// TypeError: ((p.event.special[l.origType] || {}).handle || l.handler).apply is not a function// in jQuery.min.js on Line 3
这样的错误调试起来很痛苦,不要浪费开发者的时间,直接告诉他们犯了什么错:
if (Object.prototype.toString.call(callback) !== '[object Function]') { // 看备注 throw new TypeError("callback is not a function!");}
备注:typeof callback === "function"
在老的浏览器上会有问题,object
会当成个function
。
可预测性
好的 API 具有可预测性,开发者可以根据例子推断它的用法。
Modernizr’s 特性检测 是个例子:
a) 它使用的属性名完全与 HTML5、CSS 概念和 API 相匹配
b) 每一个单独的检测一致地返回 true 或 false 值
// 所有这些属性都返回 'true' 或 'false' Modernizr.geolocation Modernizr.localstorage Modernizr.webworkers Modernizr.canvas Modernizr.borderradius Modernizr.boxshadow Modernizr.flexbox
依赖于开发者已熟悉的概念也可以达到可预测的目的。
jQuery’s 选择器语法 就是一个显著的例子,CSS1-CSS3 的选择器可直接用于它的 DOM 选择器引擎。
$("#grid") // Selects by ID$("ul.nav > li") // All LIs for the UL with class "nav"$("ul li:nth-child(2)") // Second item in each list
比例协调
好的 API 并不一定是小的 API,API 的体积大小要跟它的功能相称。
比如 Moment.js ,著名的日期解析和格式化的库,可以称之为均衡,它的 API 既简洁又功能明确。
像 Moment.js 这样特定功能的库,确保 API 的专注和小巧非常重要。
编写 API 文档
软件开发最艰难的任务之一是写文档,实际上每个人都恨写文档,怨声载道的是没有一个好用的文档工具。
以下是一些文档自动生成工具:
YUIDoc (requires Node.js, npm)
JsDoc Toolkit (requires Node.js, npm)
Markdox (requires Node.js, npm)
Dox (requires Node.js, npm)
Docco (requires Node.js, Python, CoffeeScript)
JSDuck (reqires Ruby, gem)
JSDoc 3 (requires Java)
最重要的是:确保文档跟代码同步更新。
参考资料:

微信公众号
很赞哦!(0)
相关文章
文章评论
评论0
站点信息
- 微信公众号:扫描二维码,关注我们

点击排行

标签云
-
php
网页设计
个人博客
JS
个人博客
Html
春节必看: 2020新春红包大战 全攻略
新增详细玩法攻略!
支付宝集五福5亿集分宝招商银行抽现金券抖
抖音 2020 发财中国年 攻略
支付宝集五福5亿集分宝招商银行抽现金券抖
最近购买威尔胜WTB0900复刻版和WT
mysql慢查询和php-fpm慢日志
PSR-2
基础代码规范
Thinkphp
响应式
公司
整站
源码
网络科技网站模板
1024
节日
百度收录
论坛
社区
2020
豆瓣
评分最高
电影
debugger
调试
Python
语法
高德
百度地图
MySQL
追寻
webpack
vue
oracle
服务器搭建
有趣
动物
人体
历史
天文
生活
名人
体育
地理
文化
科学
心理
植物
饮食
自然
图片
JVM
IDEA
Loader
Git
UNIAPP
股票
A股
同花顺
海尔
海天味业
半年报
股市总结
歌尔股份
乐普医疗
涪陵榨菜
餐饮
财报分析
酒店
年报分析
美锦能源
山煤国际
贵州茅台
张坤
腾讯
华鲁恒升
淮北矿业
药明康德
早盘关注
国电电力
北方华创
宝丰能源
TCL中环
兔宝宝
天润乳业
启明星辰
阳光电源
山西汾酒
迈瑞医疗
人福医药
比亚迪
宁德时代
汤臣倍健
伊利股份
通威股份
东鹏饮料
隆基股份
紫金矿业
五粮液
康龙化成
赣锋锂业
爱尔眼科
片仔癀
VR
永新股份
爱美客
美的集团
格力电器
科沃斯
云南白药
同仁堂
洋河股份
白云山
三体
狂飙 原著