JavaScript 编码指南

作者 : 开心源码 本文共6646个字,预计阅读时间需要17分钟 发布时间: 2022-05-12 共135人阅读

本文接下来的部分是少量JavaScript 指导方针,不是一成不变的法律。假如能够清晰解释代码含义,当然有很多的理由不这样做,但是,请保持警惕和自觉。他们能经过时间的检验也是有理由的:由于他们通常都是对的。偏离指南应该有好的理由,并不能简单由于突发奇想或者者个人偏好就那么做。

基本上写作的基本原则的每一部分都能应使用在代码上:

让段落成为文章的基本结构:每一段对应一个主题。

去掉无使用的单词。 .

用主动语态。

避免一连串松散的句子。

将相关的词语放在一起。

陈述句使用主动语态。

平行的概念使用平行的结构。

这些都可以使用在我们的代码风格上。

让函数成为代码的基本单元。每个函数做一件事。

去掉无使用的代码

用主动语态

避免一连串松散结构的代码

把相关的代码放在一起。

表达式和陈述语句中用主动语态。

使用并行的代码表达并行的概念。

1、让函数成为代码的基本单元。每个函数做一件事。

软件开发的本质就是写作。我们把板块、函数、数据结构组合在一起,就有了一个软件程序。

了解如何编写函数并如何构建它们,是软件开发者的基本技能。

板块是一个或者多个函数或者数据结构的简单集合,数据结构是我们如何表示程序的状态,但在没有应使用函数,数据结构自身不会发生什么有趣的事情。

JavaScript有三种类型的函数:

交流型函数:执行I/O的函数

功能型函数:一系列指令的合集

映射型函数:给少量输入,返回相应的输出

所有有使用的程序都需要I / O,并且许多程序遵循少量程序顺序,但大多数函数应该像映射函数:给定少量输入,该函数将返回少量相应的输出。

一个函数做一件事:假如你的函数是I/O敏感,那么就不要把I/O和映射(计算)混杂在一起。假如你的函数是为了映射,那么就不要加入I/O。功能性的函数就违反了这条原则。功能性的函数还违反了另一条原则:避免把松散的句子写在一起。

理想的函数应该是一个简单的,确定的,纯粹功能函数。

给定相同的输入,返回相同的输出

没有反作用

2. 去掉无使用代码

简练的代码在软件中也很重要,这是由于更多的代码让bug有了藏匿的空间。更少的代码=更少的含有bug的空间=更少bug。

简练的代码更清晰,是由于它有更高的信噪比:读者可以减少对的语法了解更多的理解它的意义。更少的代码=更少的语法噪音=更多信息的传递。

上面一段代码可以简化为:

constsecret = msg => () => msg;

对于熟习箭头函数(ES 2015年加入的新特性)的人来说,这段代码可读性加强了。它去掉了多余的语法:括号,function关键词,以及return返回值语句。

第一个版本包含了不必要的语法。对于熟习箭头语法的人来说,括号,function关键词,和return语句都没有任何意义。它们存在只是由于还有很多人对ES6的新特性不熟习。

ES6从2015年就是语言标准了。你应该熟习它了。

去掉无使用的变量

有时候我们倾向给少量实际不需要命名的变量命名。起因是人脑在可使用的容量内只能存储有限的资源,并且每个变量都必需作为离散量子存储,占据了我们可使用的不多的记忆空间。

由于这个起因,有经验的开发者都倾向减少不需要的变量命名。

比方,在大多数情况下,你应该去掉变量,只给创立一个返回值的变量。函数名应该能够提供足够多的信息以显示它的返回值。看下面的例子:

以及:

开发者常常使用来减少变量的另一个做法是:利使用函数组合以及Point-free 的风格。

Point-free 风格是指:定义函数时无需引使用对其操作的参数。常使用的point-free风格方式主要是curry和函数组合。

看一个用curry的例子:

现在看一下inc()函数。注意它并没有是有function关键词,或者者=>语法。没有参数列表,由于这个函数内部并没有用参数列表。相反的,它返回的是如何解决参数的一个函数。

下面我们看一下用函数组合的例子。函数组合是把一个函数结果应使用到另一个函数的解决流程。你可能没有意识到,你其实一直都在使用函数组合。当你调使用.map()或者者promise.then()函数的时候,你就在用它了。例如,它的大部分时候的基本形态,其实都像这样:f(g(x)).在代数中,这样的组合被写成:f ° g, 被称作“g后f”或者者“f组合g”。

当你把两个函数组合在一起时,你就去掉了需要存储的中间返回值的变量。我们看一下下面这个可以更简单的代码:

用仿函数也能实现相似的效果。用仿函数也能实现相似的效果。下面这段代码就是用仿函数的一个例子:

其实在你用promise链时,基本上就是在使用这个方法了。

实际上, 每个编程序库都至少有两个版本的实使用方法:compose ()把函数从右向左组合,pipe()函数将函数从左向右组合。

Lodash把这两个函数称作compose()和flow()。当我在Lodash里用它们时,一般都这样引入:

然而,下面的代码更少,而且完成的了同样的事情

假如函数组合对你来说像外星人一样深不可测,而且你也不确定如何用,那么请认真回顾一下前面的话:

软件开发的本质是写作。我们把板块、函数、数据结构组合在一起,就构成了软件程序。

由此你即可以得出结论:了解函数的工具意义和对象组合,就像是一个家庭手工劳动者要能了解如何用钻子和钉子枪一样的基本技能。

当你使用指令集和中间变量把不同函数组合在一起时,其实就像是使用胶布和疯狂的胶水随便的把东西沾在一起。

请记住:

假如能使用更少的代码表达相同的意思,且不改变或者混淆代码含义,那就应该这样做。

假如可以用更少变量达到相同目的,也不会改变或者混淆原意,那也应该这样做。

3.用主动语态

主动语态比被动语态更加直接、有力。 — William Strunk,Jr. 《英文写作指南》

命名越直接越好。

myFunction.wasCalled()优于myFunction.hasBeenCalled()。

createUser()优于User.create()。

notify()优于Notifier.doNotification()。

命名断言或者者布尔变量时尽量用是或者否的问题形式:

isActive(user)优于getActiveStatus(user)。

isFirstRun = false;优于firstRun = false;。

命名函数用动词形式

increment()优于plusOne()。

unzip()优于filesFromZip()。

filter(fn, array)优于matchingItemsFromArray(fn,array)。

事件解决

事件解决函数和生命周期的函数是个例外,要避免用动词形式,由于他们通常是为了说明这时该做什么而不是他们作为主语自身要做了什么。功能应该和命名一致。

element.onClick(handleClick)优于element.click(handleClick)。

component.onDragStart(handleDragStart)优于component.startDrag(handleDragStart)。

这个例子里两种命名方法的第二种,看上去更像是我们尝试触发一件事,而不是对这个事件作出响应。

生命周期函数

假设有一个组件,有这样一个生命周期函数,在它升级之前要调使用一个事件解决的函数,有以下几种命名方式:

componentWillBeUpdated(doSomething)

componentWillUpdate(doSomething)

componentWillUpdate(doSomething)

第一种命名用被动语态。这种方式有点绕口,不如其余方式直观。

第二种方式稍好,但是给人的意思是这个生命周期方法要调使用一个函数。componentWillUpdate(handler)读起来就像是这个组件要升级一个事件解决程序,这就偏离了本意。我们的原意是:”在组件升级前,调使用事件解决”beforeComponentUpdate()这样命名更为恰当清晰。

还能更精简。既然这些都是方法,那么主语(也就是组件本身)其实已经确定了。调使用这个方法时再带有主语就重复了。想象一下看到这段代码时,你会看到component.componentWillUpdate()。这就像是在说“吉米,吉米中午要吃牛排”。你其实不需要听到重复的名字。

component.beforeUpdate(doSomething)优于component.beforeComponentUpdate(doSomething)

Functional mixins?是把属性和方法增加到Object对象上的一种方法。函数一个接一个的组合增加在一起,就像是管道流一样,或者者像组装线一样。每个functional mixin的函数都有一个instance作为输入,把少量额外的东西附加上去,而后再传递给下一个函数,就像组装流水线一样。

我倾向使用描述词命名mixin 函数。你也可以用“ing”或者者“able”之类的后缀来表示描述词的含义。例如:

const duck = composeMixins(flying,quacking);

const box = composeMixins(iterable,mappable);

4、避免一连串松散的语句

开发者其实常常讲一连串的事件连接成一整个解决过程:一系列松散的语句原本就为了一个接一个而设计存在的。但过度用这样的流程会导致代码像意大利面一样错综复杂。

这种序列常常被重复,虽然会有些许的不同,有时还会出乎预料的偏离正规。例如,一个使用户界面可能会和另外的使用户界面共享了同样的组件代码。这样的代价就是代码可能被分到不同的生命周期里并且一个组件可能由多个不同的代码块进行管理。

参考下面这个例子:

constdrawUserProfile = ({ userId }) => {constuserData = loadUserData(userId);constdataToDisplay = calculateDisplayData(userData);? renderProfileData(dataToDisplay);};

这段代码做了三件事:加载数据,计算相关状态,而后渲染内容。

在现代的前台应使用框架中,这三件事是相互分离的。通过分离,每件事都可以得到比较好的组合或者者扩展。

例如,我们可以完全替换渲染器,而不使用影响其余部分;例如,React有丰富的自己设置渲染器:适使用于原生iOS和Android应使用程序的ReactNative,WebVR的AFrame,使用于服务器端渲染的ReactDOM / Server 等等。

另一个问题是你无法简单的计算要显示的数据并且假如没有第一次加载数据就无法生成显示页面。如果你已经加载了数据呢?那么你的计算逻辑就在接下来的调使用中变的多余了。

分离也使得各个部件独立可测。我喜欢给自己的应使用加很多单元测试,并且把测试结果显示出来,这样我有任何改动的时候都能看到。但是,假如我要尝试测试加载数据并渲染的功能,那我就不能只使用少量假数据测试渲染部分。正在保存……

我无法通过单元测试立刻取得结果。函数分离却可以让我们能够进行独立的测试。

这个例子就已经说明,分离函数可以让我们能够参加到应使用的不同生命周期中去。可以在应使用加载组件后,触发数据的加载功能。计算和渲染可以在视图发生变化的时候进行。

这样的结果就是更清楚地形容了软件的责任:可以重使用组件相同的结构以及生命周期的回调函数,性能也更好;在后面工作流程中,我们也节省了不必要的劳动。

5.把相关的代码放在一起。

很多框架或者者样板程序都预设了一种程序的组织方法,那就是按照文件类型划分。假如你做一个小的计算器或者者To Do的应使用,这样做没问题;但是假如是大型项目,更好的办法是按功能对文件进行分组。

下面以一个To Do 应使用为例,有两种文件组织结构。

按照文件类型分类

按照文件功能分类

按照功能组织文件,可以有效避免在文件夹视图中不断的上下滚动,直接去到功能文件夹即可以找到要编辑的文件了。

把文件按照功能进行组织。

6.陈述句和表达式用主动语态。

“做出明确的断言。避免无聊、不出彩、犹豫、不可置否的语气。用“not”时应该表达否定或者者对立面的意思,而不要使用来作为逃避的手段。”William Strunk,Jr., 《英文写作指南》。

isFlying优于isNotFlying。

late优于notOnTime。

If语句

if(err)returnreject(err);//dosomething…

比下面这种方式更好:

if(!err) {//…dosomething}else{returnreject(err);}

三元表达式

{? [Symbol.iterator]: iterator ? iterator : defaultIterator}

比下面的形式更好:

{? [Symbol.iterator]: (!iterator) ? defaultIterator : iterator}

尽量选择语气强烈的否定句

有时候我们只关系一个变量能否缺失,因而用主动语法会让我们被迫加上一个!。在这些情况下,不如用语气强烈的否定句式。“not”这个词和!的语气相对较弱。

if (missingValue)优于if (!hasValue)。

if (anonymous)优于if (!user)。

if (isEmpty(thing))优于if (notDefined(thing))。

函数调使用时避免用null和undefined参数类型

不要用undefined或者者null的参数作为函数的可选参数。尽量用可选的Object做参数。尽量用可选的Object做参数。

优于

6、用平行结构

实际应使用中,还有少量额外的问题没有处理。我们可能会重复的做同一件事情。这样的情况出现时,就有了笼统的空间。把相同的部分找出来,并笼统成可以在不同地方同时用的公共部分。这其实就是很多框架或者者功能库做的事情。

以UI控件为例来说。十几年以前,用jQuery写出把组件、逻辑应使用、网络I/O混杂在一起的代码还还很常见。而后人们开始意识到,我们可以在web应使用里也用MVC框架,于是人们逐步开始把模型从UI升级的逻辑中分离出来。

最终的结构是:web应使用用了组件化模型的方法,这让我们可以使用JSX或者者HTML模板来构建我们的UI组件。

这就让我们能够通过相同的方式去控制不同组件的升级,而无需对每一个组件的升级写重复的代码。

熟习组件化的人可以轻易的看到每个组件的工作原理:有少量代码是表示UI元素的公告性标记,也有少量使用于事件解决程序和使用在生命周期上的回调函数,这些回调函数在需要的时候会被执行。

当我们为类似的问题找到一种模式后,任何熟习这个模式的人都能很快的了解这样的代码。

结论:代码要简洁,但不是简单化。

刚健的文字是简练的。一句话应该不包含无使用的词语,一段话没有无使用的句子,正如作画不应该有多余的线条,一个机器没有多余的零件。这就要求作者尽量使用短句子,避免罗列所有细节,在大纲里就列出主题,而不是什么都说。-William Strunk,Jr.,《英文写作指南》

ES6在2015年是标准化的,但在2017年,许多开发人员避免了简洁的箭头功能,隐式回报,休息和传播操作等的功能。人们以编写更容易阅读的代码为借口,但只是由于人们更熟习旧的模式而已。这是个巨大的错误。熟习来自于实践,熟习ES6中的简洁功能显著优于ES5的起因显而易见:相比厚重的语法功能的代码,这样的代码更简洁。

代码应该简洁,而不是简单化。

简洁的代码就是:

更少的bug

更加便于调试

bug通常是这样的:

修理起来耗时耗力

可能引入更多的bug

打乱正常的工作流程

所以简洁的代码应该要:

易写

易读

易维护

让开发者学会并用新技术比方curry其实是值得的。这样做也是在让读者们熟习新知识。假如我们还是仍然使用原来的做法,这也是对阅读代码人的不尊重,就如同在使用成年人在和婴儿讲话时用孩子的口吻一样。

我们可以假设读者不了解这段代码的实现,但请不要假设阅读代码的人都很笨,或者者假设他们连这门语言都不懂。

代码应该简洁,而但不要掉价。掉价才是一种白费和侮辱。要在实践中练习,投入精力去熟习、学习一种新的编程语法、一种更有活力的风格。

代码应该简洁,而非简单化。

感谢阅读

喜欢看小编文章的点个订阅或者者喜欢!小编每天都会跟大家分享文章,也会给大家提供web前台学习资料。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » JavaScript 编码指南

发表回复