热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

15种编写自我文档化的JavaScript体式格局

在代码内里找到一个完全没有处所或没有效的解释是否是很风趣?这是一个很轻易犯的毛病:你转变了一些代码,但遗忘删除或更新解释。坏的解释不会损坏你的代码,但你能够设想一下调试时会发作什么

在代码内里找到一个完全没有处所或没有效的解释是否是很风趣?

这是一个很轻易犯的毛病:你转变了一些代码,但遗忘删除或更新解释。坏的解释不会损坏你的代码,但你能够设想一下调试时会发作什么。你读了解释,但代码却在做另一件事,也许终究你浪费了一些时刻来弄懂它,以至最坏的状况是,它误导了你。

但没有编写任何解释的代码不是一个挑选。在我凌驾15年的编程履历里,我从来没有见过一个代码库,个中的批评是完全没必要要的。

解释不仅有助于使我们的代码更轻易邃晓,也能够协助我们革新悉数顺序的设想。

这类范例的编码叫做自我文档化,如今让我来通知你怎样采纳这类体式格局编程。虽然在这里我的例子运用的是Javascript,但你能够运用到期其他的言语和手艺中去。

手艺概述

一些顺序员把解释作为代码自我文档化的一部份,在本文中,我们只关注代码,解释当然很主要,但它是一个须要零丁议论的大话题。

我们能够将代码自我文档化的手艺分为3大类:

  • structural(构造):个中代码或目次的构造用于申明目标

  • naming related(定名相干):比方函数或变量的定名

  • syntax related(语法相干):我们应用(也许防止运用)言语的特性来是代码清晰

个中许多是看起来很简朴,应战来自于你要晓得什么时刻用什么手艺。我会通知你一些现实例子,我们将会处置惩罚的每一个例子。

构造

起首,我们来看一下构造种别。构造变化时为了加强代码的清晰度而挪动代码。

将代码挪动到函数中

这与提庖代码重构雷同——意味着我们采纳现有代码并将其挪动到一个新的函数中:我们将代码提取到一个新函数中。

比方,猜测一下下面的代码是做什么的:

var width = (value - 0.5) * 16;

上述代码不是很清晰,此时解释多是异常有效的,但也许我们能够提取一个函数,使其自我文档化:

var width = emToPixels(value);
function emToPixels(ems) {
return (ems - 0.5) * 16;
}

唯一的变化时我把盘算挪动到一个函数里,函数的称号形貌了它的作用,所以代码不再须要解释。作为一个分外的优点,我们如今有了一个有效的函数,我们能够在其他处所运用这个函数,这类要领有助于削减代码反复冗余。

用函数替代前提表达式

许多时刻带有多个操作数的代码,假如没有解释是很难邃晓的。我们能够运用相似上述的要领来使代码清晰:

if(!el.offsetWidth || !el.offsetHeight) {
}

上诉前提的目标是什么?

function isVisible(el) {
return el.offsetWidth && el.offsetHeight;
}
if(!isVisible(el)) {
}

再一次,我们把代码挪动到一个函数内,代码马上更轻易邃晓。

用变量替代表达式

用变量替代某个东西相似于将代码挪动到一个函数中,而不是一个函数,此时我们只须要一个变量。
让我们再看一下if前提语句的例子:

if(!el.offsetWidth || !el.offsetHeight) {
}

我们还能够经由过程引入一个变量,而不是提取一个函数,来使我们的代码自我文档化:

var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
}

这多是比提取函数更好的挑选,比方,当你当你想要申明的逻辑关于仅在一个处所运用的某个算法异常特定时。

这类要领最罕见的是用于数字表达式:

return a * b + (c / d);

我们能够经由过程支解盘算来使上述代码更清晰:

var multiplier = a * b;
var divisor = c / d;
return multiplier + divisor;

由于我畏惧数学,设想上述的例子照样有一些算法的。在任何状况下,代码自我文档化的症结是你能够将庞杂的表达式挪动到变量中,并增添意义,不然你的代码是难以的邃晓的。

类和模块接口

类和模块的接口——即大众要领和属性,能够作为其运用的文档。

让我们来看一下这个例子:

class Box {
setState(state) {
this.state = state;
}
getState() {
return this.state;
}
}

这个类能够包含一些其他的代码。我有意坚持示例简朴,以申明大众接口是怎样自我文档化的。

你能通知我应当怎样运用这个类吗?也许有一点点作用,但它不明显。

这两个函数都有合理的名字:它们要做的是申明本身的名字。然则尽管如此,它不是很清晰你应当怎样运用它们,极能够你须要浏览更多的代码或类的文档来弄清晰。

假如我们把它改成如许:

class Box {
open() {
this.state = 'open';
}
close() {
this.state = 'closed';
}
isOpen() {
return this.state === 'open';
}
}

这是更轻易邃晓的用法,你不以为吗?注重我们只是转变了大众接口,内部示意依然与this.satte属性雷同。

如今你能够一眼就看出Box类是怎样运用的了。这表明这表明纵然第一个版本的函数具有优越的称号,但完全的包依然是杂沓的,怎样经由过程如许简朴的变化,你能够有一个异常大的影响。许多时刻你须要想一想大局。

代码分组

代码分组的差别部份也能够作为一种文档情势。

比方,你应当将变量声明尽量地接近它们被运用的位置,并尝试将变量运用组合在一起。

这能够用于指导代码差别部份之间的关联,以便未来变动它的任何人都能够更轻易地找到他们须要查阅的部份。

思索以下的例子:

var foo = 1;
blah()
xyz();
bar(foo);
baz(1337);
quux(foo);

你能一眼看出foo被挪用了多少次吗?对照下面的例子:

var foo = 1;
bar(foo);
quux(foo);
blah()
xyz();
baz(1337);

经由过程把foo的所用用处分组在一起,我们很轻易能够看出代码的哪些部份取决于它。

运用纯函数

纯函数比依靠性强的函数更轻易邃晓。

什么是纯函数?当挪用一个具有雷同参数的函数时,假如它老是发生雷同的输出,它很有多是一个“纯”函数。这意味着纯函数不该当有任何副作用或依靠状况,如时刻、对象属性、Ajax等。

这类范例的函数更轻易邃晓,由于影响其输出的任何值都邃晓通报,你没必要弄清晰个中的某个值是什么、来自那边,或什么要素会影响效果,由于它是一览无余的。

这类范例的函数发生更多的自我文档化代码的另一个原因是你能够信托他们的输出。不论什么时刻,函数老是输出基于你通报给它的参数的值,它也不会影响任何的外部代码,所以你能够置信它不会致使意想不到的副作用。

一个很好的例子是,毛病地运用document.write(),有履历的JS开发者晓得不该当运用它,然则许多初学者都被它绊倒。有时刻它事变的很好,但在其他时刻,在某些状况下,它能够把悉数页面擦清洁。谈一个副作用的痛!

为了更好地阐释纯函数是什么,能够检察Functional Programming: Pure Functions。

目次和文件构造

当定名文件或目次时,遵照项目中用到的定名商定。假如项目中没有邃晓的定名商定,请遵照您挑选的言语定名规范。

比方,你要增加有关UI的新的代码,请找到项目中安排相似功用的位置,假如UI相干的代码放在src/ui中,那你应当安排在这里。

基于你已晓得项目中的其他代码段,目次和文件构造清晰使得你更轻易找到代码, 并邃晓其目标。一切的UI代码都放在同一个处所,所以它必需是和UI相干的代码。

定名

这里有一个盛行的摘引关于盘算机科学的两个困难的方面:

There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton

那末,让我们来谈谈怎样运用合理的定名来使我们的代码自我文档化。

重定名函数

函数的定名平常不太难,这里有一些简朴的划定规矩,你能够遵照:

  • 防止运用handlemanage如许的隐约词:handleLinks(), manageObjects(),这些都做了什么?

  • 运用主动性动词:cutGrass(), sendFile()函数积极地执行了某事

  • 表明返回值:getMagicBullet(), readFile(),这不是你老是能够做到的,但给予它意义是有协助的

  • 强范例的言语能够运用范例定名来协助表明返回值

重定名变量

关于变量,这里有两个好的履历轨则:

  • 表明单元:假如有数字参数,能够包含参数的预期单元。比方,widthPX而不是width表明值得单元是像素而不是其他单元

  • 不要运用快捷体式格局:ab不是可接受的变量称号, 除了在轮回盘算器中

遵照既定的定名商定

尝试在代码中遵照雷同的定名商定。比方,假如你有一个特定范例的对象,挪用它雷同的称号:

var element = getElement();

不必倏忽以为称之为node:

var node = getElement();

假如你遵照与代码库中其他处所雷同的定名商定,浏览代码的任何人都能够基于此变量在别的处所的定名寄义安全地假定它在此处的寄义。

运用有意义的毛病

未定义不是一个对象!

每一个人的最爱。让我们抛开Javascript的例子,让我们确保代码抛出的任何毛病都是有意义的音讯。

什么能够使毛病音讯有意义?

  • 它应当形貌毛病是什么

  • 假如能够,它应当包含任何致使毛病地变量值或其他数据

  • 症结点:抛出的毛病应当协助我们找出那边出错了——因而毛病音讯应当像函数那样通知我们应当怎么做

语法

自我文档化代码的语法相干要领能够有一些言语特点。比方,Ruby和Perl许可你写一些新鲜的语法技能,平常来说,应当防止。

让我们来看几个在Javascript中碰到的题目:

不要运用语法技能

不要运用语法技能。这很轻易让人迷惑:

imTricky && doMagic();

上面的这行代码相当于以下更健全的代码:

if(imTricky) {
doMagic();
}

习气运用后一种写法,语法技能并不讨任何人的喜好。

运用常量定名,防止运用magic值

假如你的代码中有特别值——比方数字或字符串值,请斟酌运用常量定名。纵然如今看起来很清晰,但在一个月也许两个月后,没人会晓得为何这么一个特定的号码放在那边,意义是什么。

const MEANING_OF_LIFE = 42;

(假如你不运用ES6,你能够用var,是一样的。)

防止运用布尔值

布尔值会让人难以邃晓代码,斟酌这个:

myThing.setData({ x: 1 }, true);

此处true的作用是什么呢?除非找到setDate()要领并浏览它。

相反你能够增加另一个函数,或重定名现有的函数:

myThing.mergeData({ x: 1 });

如今,你马上就能够晓得这行代码发作了什么。

运用言语上风

我们以至能够运用我们编写的言语的一些特性来更好地表述代码背地的意义。

Javascript中一个很好的例子是数组的迭代:

var ids = [];
for(var i = 0; i ids.push(things[i].id);
}

上面的代码将一个ID列表收集到一个新的数组中,然则为了邃晓这块代码是做什么的,我们须要浏览悉数轮回的悉数。下面我们运用map()来举行比较:

var ids = things.map(function(thing) {
return thing.id;
});

在这类状况下,我们马上晓得这会发生一系列的新东西由于这是map()的目标。假如你有更庞杂的轮回逻辑,这是很有益的写法。list of other iteration functions on MDN

Javascript的另一个好例子是const症结字。

一般,你声明的变量值应当永久不会转变,一个罕见的例子是运用CommonJS加载模块时:

var async = require('async');

你能够用以下写法做出不糊转变企图的语句:

const async = require('async');

作为一个分外的优点,假如有人不小心试图转变这一点,我们将会获得一个毛病。

反形式

经由过程一切这些要领,你能够做许多事变,然则,有些事变你应当注重。

Extracting for the sake of having short functions

有些人主意运用简短的小函数,假如你把一切东西都提取出来,那就是你能获得的。然则,这能够不利于代码的邃晓水平。

比方,假定你正在调试一些代码。你想检察a()函数,然后你会发明b()函数,接着你会发明运用到c()函数,等等。

虽然简短的功用能够很好而且易于邃晓,但假如你只在一个处所运用该功用,那末请斟酌运用replace expression with variable要领。

别强迫

像平常那样,没有相对正确处所法来使代码自我文档化。因而,假如某些东西似乎是一个好主意,但不能强迫运用。

总结

使你的代码自我文档化能够大大提高代码的可保护性,每一个解释都是须要分外保护的,所以在有能够删除解释的状况下,编写自我文档化的代码是一个好挑选。

然则自我文档化的代码并不能庖代文档也许解释,比方,代码本身在表达企图的时刻收到限定时,你照样须要有很好的解释的。在一些库中,API文档是很主要的,因而纯真靠浏览代码是不可取的,除非你的库异常小。


推荐阅读
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • Jquery 跨域问题
    为什么80%的码农都做不了架构师?JQuery1.2后getJSON方法支持跨域读取json数据,原理是利用一个叫做jsonp的概念。当然 ... [详细]
author-avatar
外星人源码商城
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有