今天的web应用大至成千上万行的javascript代码,执行各种复杂的过程,这种演化让我们开发者必须得对可维护性有一定的认识!编写可维护性代码很重要,很多情况下我们是以他人的工作成果为基础,确保代码的可维护性,以便其他开发人员更好地工作!

1 可维护性代码的特点

  1. 可理解性:其他人可以接手代码并理解它的意图,无需原开发人员花太多时间解释!
  2. 直观性:代码中的东西一看就能明白,尽管其操作过程复杂。
  3. 可适应性:代码以一种数据上的变化不要求完全重写方法。
  4. 可扩展性:在代码架构上可对核心功能的扩展。
  5. 可调式性:出错时,代码可以给你足够的信息来直接确定问题所在。

2 代码约定

由于javascript语言的特点,我们可编写各种编程风格的代码,从传统的面向对象式到声明式到函数式。形成一套良好的javascript代码书写约定可大大提高可维护性,这点对初学者来说绝对是没有很注重的地方。

2.1 可读性

  1. 缩进:在项目中统一代码缩进,更易于阅读,一种不错也很常见的缩进大小为四个空格,当然可以是其他数量。
  2. 注释:其实我们在编写一些后台代码会经常把一个功能,一个业务逻辑,一个函数的代码注释起来,但我们却在编写javascript却经常忽略这些习惯。一般而言,在js中有以下这些地方需要注释:
  • 函数和方法 :描述其目的和参数代表,返回值等。
  • 大段的代码 :大段代码通常是一个任务的代码,应注释描述任务。
  • 复杂的算法 :不是所有人都会你的算法,你需要把你的算法思路简单描述下。
  • Hack :因各浏览器的差异,javascripthack用于解决什么问题应该描述清楚。

2.2 变量和函数的命名

  1. 变量名应该名词:如carperson
  2. 函数名应以动词开始:如getName(),返回布尔类型值的函数一般以is开头,如:isEnable();
  3. 只要合乎逻辑,不用担心变量或者函数名的长度,长度问题可以通过在你发布代码压缩的时候得以解决。

2.3 变量类型透明

var car,person; //声明两个变量

如上代码,由于javascript中变量是松散类型的,我们并不知道其中的car和person是什么类型的数据,不够透明,我们可以通过一下两种方式缓解这种问题:

  1. 初始化变量:通过初始化指定变量类型,但通过这种方式命名的对象无法用于函数声明中的参数。

    var car = null; //car是对象
    var person = ''; //person是字符串
    var count = -1; //count是整数
    var found = false; //found是布尔型
  2. 匈牙利标记法:在变量名之前加上一个或多个字符表示数据类型。o - 对象,s - 字符串,i - 整数,f - 浮点数,b - 布尔型

    var oCar; //car是对象
    var sPerson; //person是字符串
    var iCount; //count是整数
    var bFound; //found是布尔型

3 松散耦合

记得以前刚入门C#的时候,师兄经常跟我说‘高内聚低耦合’这词,我也就含糊地点点头,很多人可能也像我之前一样,这词耳熟能详,但未真正实践。

只要应用的某个部分过分依赖另一部分,代码就是耦合过紧,难于维护! 典型的问题:对象直接应用另一个对象,并且修改其中一个的同时需要修改另一个。 在我们web应用中,我们可以通过一下方式解耦我们的代码:

3.1 解耦HTML/JavaScript

在web应用中,我们希望html专注于展示数据,css专注于样式,javascript专注于行为交互。但是有一些代码会将htmljavascript过于紧密地耦合在一起。

  1. 直接写在HTMLjavascript,使用包含内联代码的<script>元素或者是使用HTML属性来分配事件处理程序。

    <!--使用<script>标签的紧密耦合 -->
    
    <script type="text/javascript">
    document.write('hello,javascript');
    </script> <!--使用时间处理程序属性值的紧密耦合 -->
    <input type="button" value="click me" onclick="doSomething()"/>

    虽然这样写完全正确,但出现javascript错误是,我们需要判断错误出现在HTML还是在Javascript中,并且这还存在一个时间差问题,当我按下上面代码的按钮时,若此时javascript代码并未加载完,此时变回引发错误。在实践中,理想的状况应该是HTMLJavascript应完全分离,使用引入外部文件来加载javascript

  2. 相反地,在javascript中也不能包含过多的HTMl

    function insertMsg(msg){
    var container = document.getElementById('container');
    container.innerHtml = '<div lcass=\"msg\"><p class=\"post\">' + msg + '</p></div>'
    }

当你在写这样的代码的时候,我想你应该去找个js模板引擎来了。

对动态生成的HTML,对书写CSS布局,定位错误都比较难把控。

3.2 解耦CSS/Javascript

上面说了,CSSJS都应该各司其职,不能有太大的亲密动作,秀恩爱,死得快 囧~~~。
这个问题并不能说完全解耦cssjs,因为在现代web应用中常常需要javascript来更改样式,但是我们还是尽量使他们分离。

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

这样的代码在以后修改样式的时候需要同时修改CSS和JS,可麻烦了。

//这样就ok了
element.className = 'color'; //color是样式类

还有一个就是不能在CSS中写CSS表达式,这应该是都知道的了。

3.3 解耦应用逻辑和事件处理程序

每个web应用程序都有相当多的事件处理程序,监听着大量不同的事件,然而,很少能有仔细将应用逻辑从事件处理程序中分离的,如下:

function checkValue(e){
e = e || window.event;
var target = e.target || e.srcElement;
if(target.value.length < 5){
//省略一堆逻辑处理代码...
}
}

将上面的代码重写为:

function checkValue(value){
if(value.length < 5){
//省略一堆逻辑处理代码...
}
}
function handleBlur(e){
e = e || window.event;
var target = e.target || e.srcElement;
checkValue(target.value); //调用应用逻辑处理函数
}

这样写有什么好处呢?

  1. 当有不同的方式触发相同的相同过程事件的时候,这时只需调用应用逻辑处理函数即可。
  2. 应用逻辑处理函数可以在不添加到事件的情况下单独测试。

4 编程实践

在企业环境中创建的web应用往往同时由大量人员一同创作。在这种情况下的目标是确保每个人所使用的浏览器环境都有一致和不变的规则,因此,我们需要坚持一下的一些编程实践:

4.1 避免全局变量

在一个js文件中,最多允许有一个全局变量,让其他对象和函数包含在其中,因为过多的全局变量会消耗大量内存。

//两个全局变量
var name = 'jozo';
function sayName(){
alert('jozo');
}

上面的代码有两个全局变量,变量name和函数sayName(),其实可以创建一个变量包含它们:

//一个全局变量 --推荐
var person = {
name:'jozo',
sayName : function(){
alert(this.name);
}
}

这样一个全局变量延伸开来就是‘空间的概念’了,不会与其他功能产生冲突,有助于消除功能作用域之间的混淆。

4.2 避免与null进行比较

function sortArray(values){
if(values != null){
values.sort(比较函数);
}
}

上面代码中的if语句应该检测values是否是数组,但如果与null作比较的话,字符串,数字等都会通过,导致函数抛出错误。这里是数组,那么我们就应该检测其是否为数组:

function sortArray(values){
if(values instanceof Array){
values.sort(比较函数);
}
}

所于当我们遇到与null作比较的代码的时候,我们应该用下面的技术替换:

  1. 如果值为引用类型,则用instanceof 操作符检查其构造函数。
  2. 如果值是基本类型,则用typeof操作符检查其类型。

4.3 使用常量

function validate(value){
if(!value){
alert('不存在');
location.href = '/errors/invalid.php';
}
}

现在,我想把‘不存在’改为‘该数据不存在!’,把跳转路径也改了,我得回到函数中找到对应的代码去修改,而每次修改逻辑代码,都有可能引入错误的风险。所以我们可以把数据单独定义为常量,与应用逻辑分离:

var Constans = {
ERRORMSG: '不存在',
ERRORPAGE:'/errors/invalid.php'
};
function validate(value){
if(!value){
alert(Constans.ERRORMSG );
location.href = Constans.ERRORPAGE ;
}
}

这样我们修改静态文本内容的时候就无需去动逻辑函数了,甚至可以把Constans单独一个文件。那么什么样的数据需要抽出来做常量呢?

  1. 重复值:任何在多处用到的值。
  2. 用户界面字符串:任何用于显示给用户提示信息的字符串。
  3. URLs:在WEB项目中,资源路径可能经常变更。在一个公共的地方存起来,修改起来更容易!
  4. 任何可能在以后会改变的值。

5 总结

所有编程语言都需要可维护性良好的代码,这个很重要,因为大部分开发人员都花费大量时间维护他人的代码。为了减轻相互的负担,从今天起我要做个好人,写好代码! o(╯□╰)o

ok,写了一遍,我印象又加深了!以上内容整理自《JavaScript高级程序设计》,觉得不错点个赞呗。下一篇将整理如何书写提高性能的JS代码。谢谢阅读……

本文转自 naraku666

[JS进阶] 编写可维护性代码 (1)的更多相关文章

  1. [ JS 进阶 ] 如何改进代码性能 (3)

    原文链接 总结一下 1.减少操作dom的次数 2.需要多次使用某全局变量的时候,将其赋给一个局部变量,避免重复查找 3.优化循环 4.多用逗号和直接赋值的方式来var,减少工厂方式和构造函数方式创建对 ...

  2. 解决VS2012编写JQuery代码不能智能提示的问题(其他js库的代码提示设置估计类似)

    VS默认设置下编写jQuery代码是这样的: 解决办法: 1.在项目的"管理NuGet程序包"中安装JQuery: 2.打开:工具 -> 选项 -> 文本编辑器 -&g ...

  3. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...

  4. Node.js进阶篇-koa、钩子函数、websocket、嵌入式开发

    代码地址如下:http://www.demodashi.com/demo/12932.html 一.简介     koa是由Express原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的We ...

  5. js进阶 13 jquery动画函数有哪些

    js进阶 13 jquery动画函数有哪些 一.总结 一句话总结: 二.jquery动画函数有哪些 原生JavaScript编写动画效果代码比较复杂,而且还需要考虑兼容性.通过jQuery,我们使用简 ...

  6. js进阶 10-3 jquery中为什么用document.ready方法

    js进阶 10-3  jquery中为什么用document.ready方法 一.总结 一句话总结: 1.document.ready和window.onload的区别:用哪个好? document. ...

  7. js进阶 10-2 JQuery基础语法是什么

    js进阶 10-2 JQuery基础语法是什么 一.总结 一句话总结: 1.jquery语法超级简单:基础语法是:$(selector).action() 2.jquery选择的时候是带了引号的,肯定 ...

  8. js进阶 10-1 JQuery是什么

    js进阶 10-1 JQuery是什么 一.总结 一句话总结: 1.两种引用jquery的方法? 可以在线jquery和本地jquery两种 2.jquery主要好处? 浏览器兼容问题 二.js进阶 ...

  9. react-native-pg-style使用方法(以最简单的方式编写样式代码,抛弃react-native标准的样式创建方式.)

    react-native-pg-style 以最简单的方式编写样式代码,抛弃react-native标准的样式创建方式. 看大家写的源码中都是按照react-native标准的样式创建方式来写样式代码 ...

随机推荐

  1. a letter and a number

    描述we define f(A) = 1, f(a) = -1, f(B) = 2, f(b) = -2, ... f(Z) = 26, f(z) = -26;Give you a letter x ...

  2. 1.6.1 什么是 Indexing

    这部分描述了建立索引的过程:添加内容到solr索引中,如果有需要,修改内容或者删除它.通过添加内容到索引里边,我们使其内容可以搜索. solr索引能够接收不同来源的数据,xml文件,逗号分隔值的(CV ...

  3. android MotionEvent中getX()和getRawX()的区别

    public class Res extends Activity implements View.OnTouchListener { Button btn = null; int x = 0; in ...

  4. GCD调度组、自定义队列来实现多个下载任务

    #define KURL1 @"http://img0.imgtn.bdimg.com/it/u=79920747,2237302485&fm=90&gp=0.jpg&quo ...

  5. Redis入门(集合)

    集合 Redis的集合是字符串的无序集合.在Redis您可以添加,删除和测试文件是否存在,在成员O(1)的时间复杂度. 例子 redis 127.0.0.1:6379> sadd tutoria ...

  6. linux_memcached_memcachedb

    三个区别 当你听到memcache与memcached时把它当做是一个东东就好了,尽管它们存在区别,但是这并不影响你对它们的运用及理解. “Memcache”它是一个自由和开放源代码.高性能.分配的内 ...

  7. Oracle基础 exp/imp 数据泵导入/导出 命令

    一.导出方式: 使用exp/imp方式导出数据分为四种方式: 1.表方式导出:一个或多个指定的表,包括表的定义.表数据.表的所有者授权.表索引.表约束,以及创建在该表上的触发器.也可以只导出结构,不导 ...

  8. C# .net 使用 SmtpClient 发邮件 ,发送邮箱的配置

    1.需打开POP3/SMTP/IMAP 2.打开时要求授权码,输入自定义的密码如:1234cb 3.自定义的密码就是  SmtpClient 的密码,而非邮箱密码

  9. CentOS 7 使用外部邮箱 发送邮件和附件—mail,mailx

    1.查看软件包是否安装 [root@localhost ~]# rpm -qa|grep mail mailx-12.5-12.el7_0.x86_64 javamail-1.4.6-8.el7.no ...

  10. 统计机器学习(statistical machine learning)

    组要组成部分:监督学习(supervised learning),非监督学习(unsupervised learning),半监督学习(semi-supervised learning),强化学习(r ...