JavaScript 的 API 设计原则

2023-06-03 0 580

(点选

译者:卖露天科夫斯基

www.cnblogs.com/constantince/p/5580003.html

但如好该文征稿,请点选 → 这儿介绍详细情况

序言

第一集昌明源自一场子公司内部的后端撷取,从数个各方面探讨了在结构设计USB时的准则,一共包涵了八个小块。系卤煮他们归纳的许多经验和教训。与此同时也参照了许多该文,门牌号会在前面诸杨。极难努力做到详细精练,假如有好的提议或是不对的地方性,还望不吝赐教斧正。

一、USB的反应速度

好的USB是简洁简练的,他主要就充分体现如下表所示两个各方面:

1.单纯

操作方式某一原素的css特性,上面是原生植物的方式:

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

PCB后

functiona(selector,color){

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

}

a(#a,red);

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

2.可阅读性

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

functionletSomeElementChangeColor(selector,color){

document.querySelectorAll(selector,color);

}

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

3.减少记忆成本

我们刚刚的函数也是这样的它太长了letSomeElementChangeColor虽然减少了映射成本,但是增加了记忆成本。要知道,包cument.querySelectorAll;这些api给人的感觉就是单词太长了,虽然他给出的意义是很清晰,然而这种做法是建立在牺牲简易性的基础上进行的。于是我们又再次改写这个之前函数

functionsetColor(selector,color){

xxxxxxxxxxxx

}

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

4.可延伸

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

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

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

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

用我们之前的之前的方式是再次PCB两个函数 setFontSize, setbackgroundColor; 然后执行它们 setColor(‘id’, ‘red’);setFontSiez(‘id’, ’12px’); setbackgroundColor(‘id’, ‘pink’); 显然,再对象的每个方式中返回这个对象:

functiongetElement(selector){

this.style = document.querySelecotrAll(selector).style;

}

getElement.prototype.color = function(color){

this.style.color = color;

returnthis;

}

getElement.prototype.background = function(bg){

this.style.backgroundColor = color;

returnthis;

}

getElement.prototype.fontSize = function(size){

this.style.fontSize = size;

returnthis;

}

//调用

varel = newgetElement(#id)

el.color(red).background(pink).fontSize(12px);

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

nightmare:

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

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

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

dream:

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

二、一致性

1.USB的一致性

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

Nightware:

setColor,

letBackGround

changefontSize

makedisplay

dream:

setColor;

setBackground;

setFontSize

set………

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

三、参数的处理

1.参数的类型

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

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

functionsetColor(color){

if(typeof color !== string)return;

dosomething

}

2.使用json方式传参

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

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

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

functionfn(json){

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

vardefault = extend({

paramdefault,

param1default

……

},json)

}

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

四、可扩展性

软件结构设计最重要的准则之一:永远不修改USB,指扩展它!可扩展性与此同时会要求USB的职责单一,多职责的USB极难扩展。 举个栗子:

//需要与此同时改变某一原素的字体和背景

// Nightmare:

functionset(selector,color){

document.querySelectroAll(selector).style.color = color;

document.querySelectroAll(selector).style.backgroundColor = color;

}

//无法扩展改函数,假如需要再次改变字体的大小的话,只能修改此函数,在函数前面填加改变字体大小的代码

//Dream

functionset(selector,color){

varel = document.querySelectroAll(selector);

el.style.color = color;

el.style.backgroundColor = color;

returnel;

}

//需要设置字体、背景颜色和大小

functionsetAgain(selector,color,px){

varel = set(selector,color)

el.style.fontSize = px;

returnel;

}

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

2.this的运用

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

functionsayBonjour(){

alert(this.a)

}

obj.a = 1;

obj.say = sayBonjour;

obj.say();//1

//or

sayBonjour.call||apply(obj);//1

五、对错误的处理

1.预见错误

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

2.抛出错误

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

functionerror(a){

if(typeofa !== string){

console.error(param a must be type of string)

}

}

functionerror(){

try{

// some code excucete here maybe throw wrong

}catch(ex){

console.wran(ex);

}

}

六、可预见性

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

//nighware

functionset(selector,color){

document.getElementById(selector).style.color = color;

}

//dream

zepto.init = function(selector,context){

vardom

// If nothing given, return an empty Zepto collection

if(!selector)returnzepto.Z()

// Optimize for string selectors

elseif(typeof selector == string){

selector = selector.trim()

// If its a html fragment, create nodes from it

// Note: In both Chrome 21 and Firefox 15, DOM error 12

// is thrown if the fragment doesnt begin with <

if(selector[0] == < && fragmentRE.test(selector))

dom = zepto.fragment(selector,RegExp.$1,context),selector = null

// If theres a context, create a collection on that context first, and select

// nodes from there

elseif(context !== undefined)return$(context).find(selector)

// If its a CSS selector, use it to select nodes.

elsedom = zepto.qsa(document,selector)

}

// If a function is given, call it when the DOM is ready

elseif(isFunction(selector))return$(document).ready(selector)

// If a Zepto collection is given, just return it

elseif(zepto.isZ(selector))returnselector

else{

// normalize array if an array of nodes is given

if(isArray(selector))dom = compact(selector)

// Wrap DOM nodes.

elseif(isObject(selector))

dom = [selector],selector = null

// If its a html fragment, create nodes from it

elseif(fragmentRE.test(selector))

dom = zepto.fragment(selector.trim(),RegExp.$1,context),selector = null

// If theres a context, create a collection on that context first, and select

// nodes from there

elseif(context !== undefined)return$(context).find(selector)

// And last but no least, if its a CSS selector, use it to select nodes.

elsedom = zepto.qsa(document,selector)

}

// create a new Zepto collection from the nodes found

returnzepto.Z(dom,selector)

}

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

七、注释和文档的可读性

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

//注释USB,为了演示PPT用

functioncommentary(){

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

vara;

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

returngo.Navigate(hash,function(){

data.clear();

});

}

最后

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

JavaScript 的 API 设计原则

卤煮在此也推荐两个在线编辑的网站。诸君可自行前往练习使用。

https://www.zybuluo.com/mdeditor

http://mahua.jser.me/

参照昌明

后端头条-javascript的api结构设计准则(http://top.css88.com/archives/814)

觉得本文对你有帮助?请撷取给更多人

JavaScript 的 API 设计原则

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务