深入浅析JavaScript的API设计原则(转载)

一、接口的流畅性

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

1.简单

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

?


1

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

封装之后

?


1

2

3

4

function a(selector, color) {

document.querySelectorAll(selector)[].style.color = color

}

a(‘#a‘, ‘red‘);

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

2.可阅读性

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

?


1

2

3

function letSomeElementChangeColor(selector, color) {

document.querySelectorAll(selector, color);

}

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

3.减少记忆成本

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

?


1

2

3

function setColor(selector, color) {

xxxxxxxxxxxx

}

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

4.可延伸

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

?


1

2

3

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方法封装成对象,然后再对象的每个方法中返回这个对象:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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:

?


1

2

3

document.getElementById(‘id‘).style.color = ‘red‘;

document.getElementById(‘id‘).style.fontSize = ‘px‘;

document.getElementById(‘id‘).style.backgourdColor = ‘pink‘;

dream:

?


1

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

二、一致性

1.接口的一致性

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

Nightware:

setColor,
letBackGround
changefontSize
makedisplay

dream:

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

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

三、参数的处理

1.参数的类型

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

?


1

2

3

4

5

//我们规定,color接受字符串类型

function setColor(color) {

if(typeof color !== ‘string‘) return;

dosomething

}

2.使用json方式传参

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

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

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

?


1

2

3

4

5

6

7

8

function fn(json) {

//为必须的参数设置默认值

var default = extend({

param: ‘default‘,

param: ‘default‘

......

},json)

}

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

四、可扩展性

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//需要同时改变某个元素的字体和背景

// 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方法的灵活运用:

?


1

2

3

4

5

6

7

8

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。

?


1

2

3

4

5

6

7

8

9

10

11

12

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

//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在这里使用了很多的是非判断,同时导致了代码的冗长,不适合阅读。总之,可预见性真正需要你做的事多写一些对位置实物的参数。把外部的检测改为内部检测。是的使用的人用起来舒心放心开心。呐!做人嘛最重要的就是海森啦。

七、注释和文档的可读性

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

?


1

2

3

4

5

6

7

8

9

//注释接口,为了演示PPT用

function commentary() {

//如果你定义一个没有字面意义的变量时,最好为它写上注释:a:没用的变量,可以删除

var a;

//在关键和有歧义的地方写上注释,犹如画龙点睛:路由到hash界面后将所有的数据清空结束函数

return go.Navigate(‘hash‘, function(){

data.clear();

});

}

最后

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

时间: 2024-11-12 06:44:45

深入浅析JavaScript的API设计原则(转载)的相关文章

JavaScript 的 API 设计原则

前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时的原则,总共包含了七个大块.系卤煮自己总结的一些经验教训.同时也参考了一些文章,地址会在后面贴出来.很难做到详尽充实,如果有好的建议或者不对的地方,还望不吝赐教斧正. 一.接口的流畅性 好的接口是流畅易懂的,他主要体现如下几个方面: 1.简单 操作某个元素的css属性,下面是原生的方法: document.querySelectorAll('#id').style.color = 'red'; 封装之后 function a(

JavaScript的api设计原则

一.接口的流畅性 好的接口是流畅易懂的,他主要体现如下几个方面: 1.简单 操作某个元素的css属性,下面是原生的方法: document.querySelector('#id').style.color = 'red'; 封装之后 function a(selector, color) {  document.querySelector(selector).style.color = color } a('#a', 'red'); 从几十个字母长长的一行到简简单单的一个函数调用,体现了api简

JavaScript API 设计原则

网+线下沙龙 | 移动APP模式创新:给你一个做APP的理由>> 好的 API 设计:在自描述的同时,达到抽象的目标. 设计良好的 API ,开发者可以快速上手,没必要经常抱着手册和文档,也没必要频繁光顾技术支持社区. 流畅的接口 方法链:流畅易读,更易理解 //常见的 API 调用方式:改变一些颜色,添加事件监听 var elem = document.getElementById("foobar"); elem.style.background = "red&

转载:阮一峰 Rest API设计原则

网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信.这导致 API 构架的流行,甚至出现"API First"的设计思想.RESTful API 是目前比较成熟的一套互联网应用程序的 API 设计理论.我以前写过一篇<理解 RESTful 架构>,探讨如何理解这个概念. 今天,我将介绍 RESTful API 的设计细节,探讨如何设计一套

*javascript开发的设计原则和设计模式

 设计原则(7种):   之所以有这么多的原则来指导我们进行程序的设计和开发,是因为我们的程序存在未知的改变.为了以最低的代价拥抱这种未知的变化,前辈们给我们总结了这么多原则. ①YAGNI原则you aren't gonna need it 不要写不需要的代码 ②KISS原则keep it simple and stupid代码保持简介和具有表现力语义话的标记.注释.变量或者方法的命名.减少嵌套 ③DRY原则Don't Repeat Yourself模块的封装提高代码的复用率 降低测试难度 方

数据库设计原则转载

1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体. 在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体. 这里的实体可以理解为基本表.明确这种对应关系后,对我们设计录入界面大有好处. [例1]:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表.社会关系表.工作简历表.   这就是“一张原始单证对应多个实体”的典型例子. 2. 主键与外键

RESTful API设计原则与规范

一.背景与基础概念 2 二.RESTful API应遵循的原则 3 1.协议(Protocol) 3 2.域名(ROOT URL) 3 3.版本(Versioning) 3 4.路径(Endpoints) 3 5.HTTP动词(HTTP Verbs) 4 6.过滤信息(Filtering) 5 7.状态码(Status Codes) 5 8.错误处理(Error handling) 6 9.返回结果(Response) 6 10.使用HATEOAS的Hypermedia API 6 11.认证(

Atitit. Api 设计 原则 ---归一化

1.1. 叫做归一化1 1.2. 归一化的实例:一切对象都可以序列化/toString  通过接口实现1 1.3. 泛文件概念.2 1.4. 游戏行业的一切皆精灵2 1.1. 叫做归一化 接口继承实质上是要求"做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象"--这在程序设计上,叫做归一化. 归一化使得外部使用者可以不加区分的处理所有接口兼容的对象集合--就好象linux的泛文件概念一样,所有东西都可以当文件处理,

数据库设计原则[转载]

转自http://www.iteye.com/topic/281611 1. 原始单据与实体之间的关系  可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体. 在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实体,或多张原始单证对应一个实体. 这里的实体可以理解为基本表.明确这种对应关系后,对我们设计录入界面大有好处. [例1]:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表.社会关系表.工作简历