教你如何写出可维护的JS代码

什么是可维护代码

可维护代码需要遵循以下几个特点。

1.可理解性-其他人可以接手代码并理解它的意图和一般途径。
2.直观性-代码中的东西一看就明白,不管其操作过程有多复杂。
3.可适应性-代码以一种数据变化不要求完全重写的方法撰写。
4.可扩展性-在代码架构上已考虑在未来允许对核心功能进行扩展。
5.可调试性-当有地方出错时,代码可以给你足够的信息快速直接找出问题的所在。

代码约定

一种让代码变得可维护的简单途径是形成一套JavaScript代码的书写约定。由于JavaScript的可适应性,代码约定对它很重要。以下小节讨论代码约定的概论。

1.可读性

要让代码可维护,首先它必须可读。可读性的大部分内容和代码缩进相关的,代码整齐的缩进能一眼看出代码块是属于那个功能的,很常见的缩进大小为4个空格,现在大部分编辑器也支持一件格式化代码。可读性另一方面是注释,一般来说,有如下一些地方需要进行注释。

  • 函数和方法-每个方法或注释都应该包含一个注释,用于描述其目的和用于完成任务所可能使用的算法。
  • 大段代码-用于完成单个任务的多行代码应该在前面放一个描述任务的注释。
  • 复杂的算法-使用独特的方式来解决某个问题加以注释来解释如何做的。
  • Hack-浏览器兼容性处理。

2.变量和函数的命名

话说在平时开发中最让人头疼的事莫过于命名了,无论是class的命名还是一些变量与方法的命名,所以有时候不得不靠一些翻译软件来帮助命名。适当给变量和函数起名字对于增加代码的可理解性和可维护性是非常重要的。命名规则一般如下:

  • 变量名应为名词如car或person。
  • 函数名应以动词开始,如getName()。
  • 返回布尔类型的函数一般用is开头,如isEnable()。
  • 常量应该用全部大写表示,如MAX_LENGTH。

3.变量类型透明

由于在JavaScript中变量是松散类型的,很容易忘记变量所包含的数据类型。合适的命名方式在一定程度上可以缓解这个问题,但是放到所有的情况下看还不够,还有三种变量数据来表示数据类型的方式。

3.3.1、初始化

当定义一个变量后,它应该被初始化一个值,来暗示它将来应该如何应用。

// 通过初始化指定变量类型
var found=false; //布尔型
var count=-1; //数字型
var name=""; //字符串
var person=null; //对象

3.3.2、使用匈牙利标记法指定变量类型

匈牙利标记法在变量名之前加上一个或多个字符来表示数据类型。js中最传统的匈牙利标记法是用单个字符来表示基本类型:0-对象,s-字符串,i-整数,f-浮点数,b-布尔类型。

// 用于指定数据类型的匈牙利命名法
var bFound //布尔型
var iCount; //数字型
var sName; //字符串
var oPerson; //对象

匈牙利命名法好处是函数参数也一样可以使用,但它缺点是让代码在某种程度上那一阅读。

3.3.3、使用类型注释

最后一种指定变量类型的方式是使用类型注释。类型注释放在变量名右边,但是在初始化前面。

// 用于指定类型的类型注释
var found /*Boolean*/ = false;
var count /*int*/ = 10;
var name /*String*/ = "Tom";
var person /*Object*/ = null;

缺点:多行注释会与代码块冲突

这三种常见的指定变量数据类型的方法,各有优势与劣势,根据自己项目加以评估再进行使用,也可以学习使用下TypeScript。

松散耦合

只要应用的某个部分过分依赖另一部分,代码就是偶尔过紧,难以维护。因为Web应用技术,有多种情况回使它变得耦合过紧,因此应该避免这些情况,并尽可能维护弱耦合代码。

1.解耦html/JavaScript

直接在html中的javaScript,使用包含内联代码的<script>元素或者是使用HTML属性来分配事件处理顺序,都是过于紧密耦合。

看看以下的代码

<button onclick="doSomeThing()">Click Me</button>

在这个例子中,可能在doSomeThing()函数可用之前,就已经按下按钮,导致js错误,因为任何对按钮行为的更改要同时触及HTML和js,影响可维护性。

同理js中包含大量的HTML

// 将HTML紧密耦合到js中
function insertMessage(){
  document.getElementById('container').innerHTML='<div>Hello World</div>'
}

这段代码的方法会动态生成一段代码块插入到页面中,当代码很多时候难以定位到错误。

将 HTML 和 JavaScript 解耦可以在调试过程中节省时间,更加容易确定错误的来源,也减轻维护的难度:更改行为只需要在 JavaScript 文件中进行,而更改标记则只要在渲染文件中

2.解耦css/JavaScript

另一个 Web 层则是css,它主要负责页面的显示。JavaScript 和 CSS 也是非常紧密相关的:他们都是 HTML 之上的层次,因此常常一起使用。但是,和 HTML 与 JavaScript 的情况一样,CSS 和 JavaScript也可能会过于紧密地耦合在一起。最常见的紧密耦合的例子是使用 JavaScript 来更改某些样式,如下所示:

//CSS 对 JavaScript 的紧密耦合
element.style.color = "red";
element.style.backgroundColor = "blue";

遇到这种直接修改css样式的,我们直接可以通过修改元素标签class类名来控制样式更方便。

3.解耦应用逻辑/事件处理程序

每个 Web 应用一般都有相当多的事件处理程序,监听着无数不同的事件。然而,很少有能仔细得将应用逻辑从事件处理程序中分离的。请看以下例子:

function handleKeyPress(event) {
        event = EventUtil.getEvent(event);
        if (event.keyCode == 13) {
            var target = EventUtil.getTarget(event);
            var value = 5 * parseInt(target.value);
            if (value > 10) {
                document.getElementById("error-msg").style.display = "block";
            }
        }
    }

这个事件处理程序除了包含了应用逻辑,还进行了事件的处理。这种方式的问题有其双重性。首先,除了通过事件之外就再没有方法执行应用逻辑,这让调试变得困难。如果没有发生预想的结果怎么办?是不是表示事件处理程序没有被调用还是指应用逻辑失败?其次,如果一个后续的事件引发同样的应用逻辑,那就必须复制功能代码或者将代码抽取到一个单独的函数中。无论何种方式,都要作比实际所需更多的改动。

较好的方法是将应用逻辑和事件处理程序相分离,这样两者分别处理各自的东西。一个事件处理程序应该从事件对象中提取相关信息,并将这些信息传送到处理应用逻辑的某个方法中。例如,前面的代码可以被重写为:

 function validateValue(value) {
        value = 5 * parseInt(value);
        if (value > 10) {
            document.getElementById("error-msg").style.display = "block";
        }
    }

    function handleKeyPress(event) {
        event = EventUtil.getEvent(event);
        if (event.keyCode == 13) {
            var target = EventUtil.getTarget(event);
            validateValue(target.value);
        }
    }

应用和业务逻辑之间松散耦合的几条原则:

  • 勿将 event 对象传给其他方法;只传来自 event 对象中所需的数据;
  • 任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行;
  • 任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑。

牢记这几条可以在任何代码中都获得极大的可维护性的改进,并且为进一步的测试和开发制造了很多可能。

编程实践

书写可维护的 JavaScript 并不仅仅是关于如何格式化代码;它还关系到代码做什么的问题。在企业环境中创建的 Web 应用往往同时由大量人员一同创作。这种情况下的目标是确保每个人所使用的浏览器环境都有一致和不变的规则。因此,最好坚持以下一些编程实践。

1.尊重对象所有权

JavaScript 的动态性质使得几乎任何东西在任何时间都可以修改。也许在企业环境中最重要的编程实践就是尊重对象所有权,它的意思是你不能修改不属于你的对象。简单地说,如果你不负责创建或维护某个对象、它的对象或者它的方法,那么你就不能对它们进行修改。更具体地说:

  • 不要为实例或原型添加属性;
  • 不要为实例或原型添加方法;
  • 不要重定义已存在的方法。

2.避免全局变量

与尊重对象所有权密切相关的是尽可能避免全局变量和函数。这也关系到创建一个脚本执行的一致的和可维护的环境。最多创建一个全局变量,让其他对象和函数存在其中。请看以下例子:

// 两个全局量——避免!!
var name = "Nicholas";
function sayName(){
 alert(name);
} 

这段代码包含了两个全局量:变量 name 和函数 sayName()。其实可以创建一个包含两者的对象,如下例所示:

// 一个全局量——推荐
var MyApplication = {
 name: "Nicholas",
 sayName: function(){
 alert(this.name);
 }
}; 

这段重写的代码引入了一个单一的全局对象 MyApplication,name 和 sayName()都附加到其上。这样做消除了一些存在于前一段代码中的一些问题。首先,变量 name 覆盖了 window.name 属性,可能会与其他功能产生冲突;其次,它有助消除功能作用域之间的混淆。调用 MyApplication.sayName()在逻辑上暗示了代码的任何问题都可以通过检查定义 MyApplication 的代码来确定。

3.使用常量

以下一些类型的值适合使用常量来定义:

  • 重复值——任何在多处用到的值都应抽取为一个常量。这就限制了当一个值变了而另一个没变的时候会造成的错误。这也包含了 CSS 类名。
  • 用户界面字符串 —— 任何用于显示给用户的字符串,都应被抽取出来以方便国际化。
  • URLs ——在 Web 应用中,资源位置很容易变更,所以推荐用一个公共地方存放所有的URL。
  • 任意可能会更改的值 —— 每当你在用到字面量值的时候,你都要问一下自己这个值在未来是不是会变化。如果答案是“是”,那么这个值就应该被提取出来作为一个常量。

以上就是教你如何写出可维护的JS代码的详细内容,更多关于写出可维护的JS代码的资料请关注我们其它相关文章!

(0)

相关推荐

  • 聊一聊JavaScript的URL对象是什么

    概述 如果我们自己编写从URL中分析和提取元素的代码,那么有可能会比较痛苦和麻烦.程序员作为这个社会中最"懒"的群体之一,无休止的重复造轮子必然是令人难以容忍的,所以大多数浏览器的标准库中都已经内置了URL对象. 那么现在,有了它,我们就可以将URL字符串作为参数传递给URL的构造函数,并创建它的实例解析URL内容了吗?答案是:"是的!". 要使用URL构造函数创建URL对象,我们在以下代码中使用new来创建: new URL('https://www.grapec

  • JavaScript中正则表达式的实际应用详解

    实际工作中,JavaScript正则表达式还是经常用到的.所以这部分的知识是非常重要的. 一.基础语法: 第一种:字面量语法 var expression=/pattern/flags; 第二种:RegExp构造函数语法 var pattern = /\w/gi; //字面量语法 var pattern = new RegExp('\\w', 'gi');//构造函数语法,这两者是等价的 这里有个注意点就是:如果正则表达式是动态的话,只能选择第二种. 其中的flags有3个标志 g:表示全局模式

  • 如何用JavaScript实现一个数组惰性求值库

    概述 在编程语言理论中,惰性求值(英语:Lazy Evaluation),又译为惰性计算.懒惰求值,也称为传需求调用(call-by-need),是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作.它有两个相关而又有区别的含意,可以表示为"延迟求值"和"最小化求值",除可以得到性能的提升外,惰性计算的最重要的好处是它可以构造一个无限的数据类型. 看到函数式语言里面的惰性求值,想自己用JavaScript写一个最简实现,加深对惰性求值了解.用了两种方法,

  • 详解Javascript实践中的命令模式

    定义 Encapsulate a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests,and support undoable operations." 「命令模式」将「请求」封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象,同时支持可撤消的操作. 这里的「请求」的定义,并不是我们前端常说的「Ajax 请求

  • 如何制作自己的原生JavaScript路由

    前言 当你想到路由时,通常会想到类似react之类的库.但实际上,这些库和框架仍然使用vanillaJavaScript.那么该怎么实现呢? 我希望这个"JavaScript路由教程"能够帮你了解如何用原生js写出自己的路由. 简介 我遇到了很多出于各种原因想要自己创建路由的人.既然你看到本文,那意味着你可能也是其中的一个! 最重要的是,使用vanillajsrouter可以减少你对框架的依赖. 只要你了解实现它所涉及的所有部分,就可以相对容易的在原生 JavaScript 中创建自己

  • 如何用JavaScript学习算法复杂度

    概述 在本文中,我们将探讨 "二次方" 和 "n log(n)" 等术语在算法中的含义. 在后面的例子中,我将引用这两个数组,一个包含 5 个元素,另一个包含 50 个元素.我还会用到JavaScript中方便的performance API来衡量执行时间的差异. const smArr = [5, 3, 2, 35, 2]; const bigArr = [5, 3, 2, 35, 2, 5, 3, 2, 35, 2, 5, 3, 2, 35, 2, 5, 3,

  • 用几道面试题来看JavaScript执行机制

    前面的话 根据JavaScript的运行环境,锁定它为单线程,任务需要排队执行,如果网站资源比较大,这样会导致浏览器加载会很慢,但实际上并没有,大家肯定立刻想到了同步和异步. 所谓的同步和异步也是在排队,只是排队的地方不同. 同步和异步 同步任务进入主线程排队,异步任务进入事件队列中排队 同步任务和异步任务进入到不同的队列中,也就是上面讲的在不同地方排队. 同步任务进入主线程,异步任务进入事件队列,主线程任务执行完毕,事件队列中有等待执行的任务进入主线程执行,直到事件队列中任务全部执行完毕. 开

  • 使用 JavaScript 创建可维护的幻灯片效果代码第1/3页

    第一步:分析问题(Analizing the problem) 创建一个好的脚本,第一步应该是去分析哪些是你要完成的:我们想要创建一个照片的幻灯片效果,并且我们想要保持维护的方便. 如何创建一个幻灯片效果 在一个网站上拥有幻灯片有几种方法: 在文档中包含所有的图片.  当他运行在无 JavaScript 状态,这是一个安全的选择.而且,当页面被载完,所有的图片也会将被载完.然而,这个方式只适用于少量的图片. 在文档中包含第一张图片,并且有一个创建幻灯片功能的服务器端脚本.  这也是相当安全的,但

  • 编写可维护面向对象的JavaScript代码[翻译]

    Writing maintainable Object-Oriented (OO) JavaScript will save you money and make you popular. Don't believe me? Odds are that either you or someone else will come back and work with your code. Making that as painless an experience as possible will s

  • 教你如何写出可维护的JS代码

    什么是可维护代码 可维护代码需要遵循以下几个特点. 1.可理解性-其他人可以接手代码并理解它的意图和一般途径. 2.直观性-代码中的东西一看就明白,不管其操作过程有多复杂. 3.可适应性-代码以一种数据变化不要求完全重写的方法撰写. 4.可扩展性-在代码架构上已考虑在未来允许对核心功能进行扩展. 5.可调试性-当有地方出错时,代码可以给你足够的信息快速直接找出问题的所在. 代码约定 一种让代码变得可维护的简单途径是形成一套JavaScript代码的书写约定.由于JavaScript的可适应性,代

  • 如何写出优美的C语言代码

    面向对象的语言更接近人的思维方式,而且在很大程度上降低了代码的复杂性,同时提高了代码的可读性和可维护性,传统的 C 代码同样可以设计出比较易读,易维护,复杂度较低的优美代码,本文将通过一个实际的例子来说明这一点. 基础知识 结构体 除了提供基本数据类型外,C 语言还提供给用户自己定制数据类型的能力,那就是结构体,在 C 语言中,你可以用结构体来表示任何实体.结构体正是面向对象语言中的类的概念的雏形,比如: typedef struct{ float x; float y; }Point; 定义了

  • Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码

    美国时间 09 月 25 日,Oralce 正式发布了 Java 11,这是据 Java 8 以后支持的首个长期版本.非常值得大家的关注,可以通过下面的地址进行下载: https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html 为什么说是长期版本,看下面的官方发布的支持路线图表. 可以看出 Java 8 扩展支持到 2025 年,而 Java 11 扩展支持到 2026 年. 现在大部

  • 非常不错的弹出一个div的js代码

    LIGHTBOX EXAMPLE .black_overlay{ display: none; position: absolute; top: 0%; left: 0%; width: 100%; height: 100%; background-color: black; z-index:1001; -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80); } .white_content { display: none; posi

  • 防止登录页面出现在frame中js代码

    在使用frame页面嵌套开发的时候,遇到重启了服务器的时候会出现登录页面在frame页面中出现, 所以需要在登录页面里面用js判断下当前的地址信息,然后跳转到登录的单独页面中. js代码如下: $("document").ready(function(){ //防止在frame里面出现登录页面 if(top.location!==self.location){ //alert(top.location); //alert(self.location); top.location.hre

  • 12条写出高质量JS代码的方法

    书写出高质量的JS代码不仅让程序员看着舒服,更加能够提高程序的运行速度,以下就是我们的小编整理方法: 一.如何书写可维护性的代码 当出现bug的时候如果你能立马修复它是最好的,此时解决问题的四路在你脑中还是很清晰的.否则,你转移到其他任务或者bug是经过一定的时间才出现的,你忘了那个特定的代码,一段时间后再去查看这些代码就 需要: 1.花时间学习和理解这个问题 2.化时间是了解应该解决的问题代码 还有个问题,特别对于大的项目或是公司,修复bug的这位伙计不是写代码的那个人(且发现bug和修复bu

  • Android实用小技巧之利用Lifecycle写出更好维护的代码

    目录 前言 场景 优化版本1 优化版本2 单元测试 总结 前言 你是否在onStart()启动过某项任务却忘记在onStop()中取消呢?人不是机器,难免会有错漏.就算老手不会犯错,也不能保证新人不会.学会下面的小技巧,让这种粗心成为不可能. 关于Lifecycle的源码,已经有很多大佬分析过.这篇文章的主旨是让读者对Lifecycle的使用场景有更多的体会,这样也能更好地理解源码.先来看一个场景,然后一步一步优化. 场景 假设我们有一个界面,模拟一个厨房.里面有灶台和餐桌.要求每秒钟翻炒一下,

  • 一篇文章教你写出干净的JavaScript代码

    目录 1. 变量 使用有意义的名称 避免添加不必要的上下文 避免硬编码值 2. 函数 使用有意义的名称 使用默认参数 限制参数的数量 避免在一个函数中做太多事情 避免使用布尔标志作为参数 避免写重复的代码 避免副作用 3. 条件语句 使用非负条件 尽可能使用简写 避免过多分支 优先使用 map 而不是 switch 语句 4.并发 避免回调 5. 错误处理 6.注释 只注释业务逻辑 使用版本控制 总结 一段干净的代码,你在阅读.重用和重构的时候都能非常轻松.编写干净的代码非常重要,因为在我们日常

  • 写出高质量软件的75条体会

    如何用正确的方法写出高质量软件的75条体会 1. 你们的项目组使用源代码管理工具了么? MVM:应该用.VSS.CVS.PVCS.ClearCase.CCC/Harvest.FireFly都可以.我的选择是VSS. 2. 你们的项目组使用缺陷管理系统了么? MVM:应该用.ClearQuest太复杂,我的推荐是BugZilla. 3. 你们的测试组还在用Word写测试用例么? MVM:不要用Word写测试用例(Test Case).应该用一个专门的系统,可以是Test Manager,也可以是自

  • Javascript异步编程的4种方法让你写出更出色的程序

    你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推.  这种模式的好处是实现起来比较简单,执行环境相对单纯:坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行.常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其

随机推荐