深入浅析JavaScript的API设计原则


Posted in Javascript onJune 14, 2016

一、接口的流畅性

好的接口是流畅易懂的,他主要体现如下几个方面:

1.简单

操作某个元素的css属性,下面是原生的方法:

document.querySelectorAll('#id').style.color = 'red';

封装之后

function a(selector, color) {
document.querySelectorAll(selector)[].style.color = color
}
a('#a', 'red');

从几十个字母长长的一行到简简单单的一个函数调用,体现了api简单易用

2.可阅读性

a('#a', 'red')是个好函数,帮助我们简单实用地改变某个元素,但问题来了,如果第一次使用改函数的人来说会比较困惑,a函数是啥函数,没有人告诉他。开发接口有必要知道一点,人都是懒惰的,从颜色赋值这个函数来说,虽然少写了代码,但是增加了记忆成本。每次做这件事情的时候都需要有映射关系。 a---->color. 如果是简单的几个无所谓,但是通常一套框架都有几十甚至上百的api,映射成本增加会使得程序员哥哥崩溃。 我们需要的就是使得接口有意义,下面我们改写一下a函数:

function letSomeElementChangeColor(selector, color) {
document.querySelectorAll(selector, color);
}

letSomeElementChangeColor相对于a来说被赋予了语言意义,任何人都会知道它的意义

3.减少记忆成本

我们刚刚的函数也是这样的它太长了letSomeElementChangeColor虽然减少了映射成本,但是增加了记忆成本。要知道,包括学霸在内,任何人都不喜欢被单词。原生获取dom的api也同样有这个问题 document.getElementsByClassName; document.getElementsByName; document.querySelectorAll;这些api给人的感觉就是单词太长了,虽然他给出的意义是很清晰,然而这种做法是建立在牺牲简易性的基础上进行的。于是我们又再次改写这个之前函数

function setColor(selector, color) {
xxxxxxxxxxxx
}

在意义不做大的变化前提下,缩减函数名称。使得它易读易记易用;

4.可延伸

所谓延伸就是指函数的使用像流水一样按照书写的顺序执行形成执行链条:

document.getElementById('id').style.color = 'red';
document.getElementById('id').style.fontSize = 'px';
document.getElementById('id').style.backgourdColor = 'pink';

用我们之前的之前的方法是再次封装两个函数 setFontSize, setbackgroundColor; 然后执行它们 setColor('id', 'red');setFontSiez('id', '12px'); setbackgroundColor('id', 'pink'); 显然,这样的做法没有懒出境界来;id元素每次都需要重新获取,影响性能,失败;每次都需要添加新的方法 失败 每次还要调用这些方法,还是失败。下面我们将其改写为可以延伸的函数 首先将获取id方法封装成对象,然后再对象的每个方法中返回这个对象:

function getElement(selector) {
this.style = document.querySelecotrAll(selector).style;
}
getElement.prototype.color = function(color) {
this.style.color = color;
return this;
}
getElement.prototype.background = function(bg) {
this.style.backgroundColor = color;
return this;
}
getElement.prototype.fontSize = function(size) {
this.style.fontSize = size;
return this;
}
//调用
var el = new getElement('#id')
el.color('red').background('pink').fontSize('px');

简单、流畅、易读后面我们会在参数里面讲到如何继续优化。所以,大家都比较喜欢用jquery的api,虽然一个$符号并不代表任何现实意义,但简单的符号有利于我们的使用。它体现了以上的多种原则,简单,易读,易记,链式写法,多参处理。

nightware:

document.getElementById('id').style.color = 'red';
document.getElementById('id').style.fontSize = 'px';
document.getElementById('id').style.backgourdColor = 'pink';

dream:

$('id').css({color:'red', fontSize:'12px', backgroundColor:'pink'})

二、一致性

1.接口的一致性

相关的接口保持一致的风格,一整套 API 如果传递一种熟悉和舒适的感觉,会大大减轻开发者对新工具的适应性。 命名这点事:既要短,又要自描述,最重要的是保持一致性 “在计算机科学界只有两件头疼的事:缓存失效和命名问题” — Phil Karlton 选择一个你喜欢的措辞,然后持续使用。选择一种风格,然后保持这种风格。

Nightware:

setColor,
letBackGround
changefontSize
makedisplay

dream:

setColor;
setBackground;
setFontSize
set.........

尽量地保持代码风格和命名风格,使人读你的代码像是阅读同一个人写的文章一样。

三、参数的处理

1.参数的类型

判断参数的类型为你的程序提供稳定的保障

//我们规定,color接受字符串类型
function setColor(color) {
if(typeof color !== 'string') return;
dosomething
}

2.使用json方式传参

使用json的方式传值很多好处,它可以给参数命名,可以忽略参数的具体位置,可以给参数默认值等等 比如下面这种糟糕的情况:

function fn(param1, param2...............paramN)

你必须对应地把每一个参数按照顺序传入,否则你的方法就会偏离你预期去执行,正确的方法是下面的做法。

function fn(json) {
//为必须的参数设置默认值
var default = extend({
param: 'default',
param: 'default'
......
},json)
}

这段函数代码,即便你不传任何参数进来,他也会预期运行。因为在声明的时候,你会根据具体的业务决定参数的缺省值。

四、可扩展性

软件设计最重要的原则之一:永远不修改接口,指扩展它!可扩展性同时会要求接口的职责单一,多职责的接口很难扩展。 举个栗子:

//需要同时改变某个元素的字体和背景 
// Nightware:
function set(selector, color) {
document.querySelectroAll(selector).style.color = color;
document.querySelectroAll(selector).style.backgroundColor = color;
}
//无法扩展改函数,如果需要再次改变字体的大小的话,只能修改此函数,在函数后面填加改变字体大小的代码
//Dream
function set(selector, color) {
var el = document.querySelectroAll(selector);
el.style.color = color;
el.style.backgroundColor = color;
return el;
}
//需要设置字体、背景颜色和大小
function setAgain (selector, color, px) {
var el = set(selector, color)
el.style.fontSize = px;
return el;
}

以上只是简单的添加颜色,业务复杂而代码又不是你写的时候,你就必须去阅读之前的代码再修改它,显然是不符合开放-封闭原则的。修改后的function是返回了元素对象,使得下次需要改变时再次得到返回值做处理。

2.this的运用

可扩展性还包括对this的以及call和apply方法的灵活运用:

function sayBonjour() {
alert(this.a)
}
obj.a = ;
obj.say = sayBonjour;
obj.say();//
//or
sayBonjour.call||apply(obj);//

五、对错误的处理

1.预见错误

可以用 类型检测 typeof 或者try...catch。 typeof 会强制检测对象不抛出错误,对于未定义的变量尤其有用。

2.抛出错误

大多数开发者不希望出错了还需要自己去找带对应得代码,最好方式是直接在console中输出,告诉用户发生了什么事情。我们可以用到浏览器的输出api:console.log/warn/error。你还可以为自己的程序留些后路: try...catch。

function error (a) {
if(typeof a !== 'string') {
console.error('param a must be type of string')
}
}
function error() {
try {
// some code excucete here maybe throw wrong 
}catch(ex) {
console.wran(ex);
}
}

六、可预见性

可预见性味程序接口提供健壮性,为保证你的代码顺利执行,必须为它考虑到非正常预期的情况。我们看下不可以预见的代码和可预见的代码的区别用之前的setColor

//nighware
function set(selector, color) {
document.getElementById(selector).style.color = color;
}
//dream
zepto.init = function(selector, context) {
var dom
// If nothing given, return an empty Zepto collection
if (!selector) return zepto.Z()
// Optimize for string selectors
else if (typeof selector == 'string') {
selector = selector.trim()
// If it's a html fragment, create nodes from it
// Note: In both Chrome and Firefox , DOM error 
// is thrown if the fragment doesn't begin with <
if (selector[] == '<' && fragmentRE.test(selector))
dom = zepto.fragment(selector, RegExp.$, context), selector = null
// If there's a context, create a collection on that context first, and select
// nodes from there
else if (context !== undefined) return $(context).find(selector)
// If it's a CSS selector, use it to select nodes.
else dom = zepto.qsa(document, selector)
}
// If a function is given, call it when the DOM is ready
else if (isFunction(selector)) return $(document).ready(selector)
// If a Zepto collection is given, just return it
else if (zepto.isZ(selector)) return selector
else {
// normalize array if an array of nodes is given
if (isArray(selector)) dom = compact(selector)
// Wrap DOM nodes.
else if (isObject(selector))
dom = [selector], selector = null
// If it's a html fragment, create nodes from it
else if (fragmentRE.test(selector))
dom = zepto.fragment(selector.trim(), RegExp.$, context), selector = null
// If there's a context, create a collection on that context first, and select
// nodes from there
else if (context !== undefined) return $(context).find(selector)
// And last but no least, if it's a CSS selector, use it to select nodes.
else dom = zepto.qsa(document, selector)
}
// create a new Zepto collection from the nodes found
return zepto.Z(dom, selector)
}

以上是zepto的源码,可以看见,作者在预见传入的参数时做了很多的处理。其实可预见性是为程序提供了若干的入口,无非是一些逻辑判断而已。zepto在这里使用了很多的是非判断,同时导致了代码的冗长,不适合阅读。总之,可预见性真正需要你做的事多写一些对位置实物的参数。把外部的检测改为内部检测。是的使用的人用起来舒心放心开心。呐!做人嘛最重要的就是海森啦。

七、注释和文档的可读性

一个最好的接口是不需要文档我们也会使用它,但是往往接口量一多和业务增加,接口使用起来也会有些费劲。所以接口文档和注释是需要认真书写的。注释遵循简单扼要地原则,给多年后的自己也给后来者看:

//注释接口,为了演示PPT用
function commentary() {
//如果你定义一个没有字面意义的变量时,最好为它写上注释:a:没用的变量,可以删除
var a;
//在关键和有歧义的地方写上注释,犹如画龙点睛:路由到hash界面后将所有的数据清空结束函数
return go.Navigate('hash', function(){
data.clear();
});
}

最后

推荐markdown语法书写API文档,github御用文档编写语法。简单、快速,代码高亮、话不多说上图

深入浅析JavaScript的API设计原则

以上所述是小编给大家介绍的JavaScript的API设计原则的全部叙述,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Auntion-TableSort国人写的一个javascript表格排序的东西
Nov 12 Javascript
JavaScript 事件冒泡简介及应用
Jan 11 Javascript
Jquery 插件学习实例1 插件制作说明与tableUI优化
Apr 02 Javascript
JS在IE下缺少标识符的错误
Jul 23 Javascript
BootStrap selectpicker
Jun 20 Javascript
简单谈谈Javascript函数中的arguments
Feb 09 Javascript
javascript将url解析为json格式的两种方法
Aug 18 Javascript
bootstrap multiselect下拉列表功能
Aug 22 Javascript
ajax与jsonp的区别及用法
Oct 16 Javascript
解决vue2 在mounted函数无法获取prop中的变量问题
Nov 15 Javascript
vue微信分享出来的链接点开是首页问题的解决方法
Nov 28 Javascript
this.$toast() 了解一下?
Apr 18 Javascript
jQuery.Callbacks()回调函数队列用法详解
Jun 14 #Javascript
基于gulp合并压缩Seajs模块的方式说明
Jun 14 #Javascript
JS去除空格和换行的正则表达式(推荐)
Jun 14 #Javascript
javascript用正则表达式过滤空格的实现代码
Jun 14 #Javascript
三种带箭头提示框总结实例
Jun 14 #Javascript
js判断输入字符串是否为空、空格、null的方法总结
Jun 14 #Javascript
简单实现的JQuery文本框水印插件
Jun 14 #Javascript
You might like
php zip文件解压类代码
2009/12/02 PHP
PHP中return 和 exit 、break和contiue 区别与用法
2012/04/09 PHP
PHP使用Redis长连接的方法详解
2018/02/12 PHP
PHP大文件分块上传功能实例详解
2019/07/22 PHP
设定php简写功能的方法
2019/11/28 PHP
Yii框架安装简明教程
2020/05/15 PHP
PHP实现简易用户登录系统
2020/07/10 PHP
jquery动态添加删除div 具体实现
2013/07/20 Javascript
解决js数据包含加号+通过ajax传到后台时出现连接错误
2013/08/01 Javascript
关于javascript event flow 的一个bug详解
2013/09/17 Javascript
jquery快捷动态绑定键盘事件的操作函数代码
2013/10/17 Javascript
七个很有意思的PHP函数
2014/05/12 Javascript
Jquery之Bind方法参数传递与接收的三种方法
2014/06/24 Javascript
深度了解vue.js中hooks的相关知识
2019/06/14 Javascript
layer.open组件获取弹出层页面变量、函数的实例
2019/09/25 Javascript
Python编程之gui程序实现简单文件浏览器代码
2017/12/08 Python
使用python爬虫获取黄金价格的核心代码
2018/06/13 Python
Python使用统计函数绘制简单图形实例代码
2019/05/15 Python
Python设置matplotlib.plot的坐标轴刻度间隔以及刻度范围
2019/06/25 Python
pyqt5 QScrollArea设置在自定义侧(任何位置)
2019/09/25 Python
Pyqt5自适应布局实例
2019/12/13 Python
科沃斯机器人官网商城:Ecovacs
2016/08/29 全球购物
工程预算与管理应届生求职信
2013/10/06 职场文书
应聘面试自我评价
2014/01/24 职场文书
党的群众路线教育实践活动个人整改措施范文
2014/11/04 职场文书
体育教师个人总结
2015/02/09 职场文书
结婚老公保证书
2015/02/26 职场文书
幼师辞职信范文
2015/02/27 职场文书
2015年行风建设工作总结
2015/05/15 职场文书
小学运动会报道稿
2015/07/22 职场文书
赞美教师的句子
2019/09/02 职场文书
解决Python字典查找报Keyerror的问题
2021/05/26 Python
教你如何使用Python开发一个钉钉群应答机器人
2021/06/21 Python
一篇文章告诉你如何实现Vue前端分页和后端分页
2022/02/18 Vue.js
golang生成vcf通讯录格式文件详情
2022/03/25 Golang
python 学习GCN图卷积神经网络
2022/05/11 Python