第一部分: 编程风格

在大型项目开发中,因为项目可读性规范性的需要(就像《编写可维护性的Javascript》一书作者Nicholas Zakas大神所说,他们团队所有成员写出的代码就像是经同一个人之手写出的一样),风格约定要大于个人喜好这一点毋庸置疑,不过什么样才是好的编程风格约定?下面推荐一些实践中沉淀下来的代码规范和最佳实践:

缩进
  • 缩进问题和编辑器问题一样是一个因为个人喜好和其他不管值得不值得争执的理由而存在争议的问题,目前存在两个流派,空格流和tab流。个人比较习惯于tab(4个空格距离),在这个问题上团队有协商的余地,不过关键还是两个字:一致。

  • 一行截断成两行后,第2行开头缩进2个tab距离。

// 截断缩进用2个tab
var str = "abcdefghijkl" +
"mnopqrstuvwxyz";
  • =号后面截断到下一行的开头要和前一行=号后面的第一个字母左对齐。
// =截断和上一行=号对齐
var s1 = s2
= s3;
  • 函数用小写开头(Camel case),构造函数用大写开头(Pascal case)。
  • 语句块的写法:()两边留空格,{}两边留空格。
// 块语句的空格规范
if (flag === true) {
alert('Yep!');
} else {
alert('Nop!');
}
和NULL做比较
  • 只在期待null值的时候和null做比较,比如在一个函数里返回一个null作为期待返回的对象的值。这时可以使用if (res === null) 或者 if( res !== null)来做判断。其他情况尽量不要用null来做检测。注意这里用的是===而不是==号来比较,因为undfined==null的结果是true,而null和undefined有着天壤之别,后面会提到。
  • 尽量避免在代码中使用undefined,undefined表示变量未被初始化,或者变量未声明,也表示值是undefined的变量。而typeof运算符在检测以上三种情况时返回的都是undefined
// 不好的用法:和undefined比较
var cat;
if(cat === undefined) {
doSomething();
}

尽管上面的代码能够正常运行,但是好的方式是下面这种:

// 好的用法,初始化为null
var cat = null;
if(cat === null) {
doSomething();
}

这里不存在如上所述undefined的多种可能的混淆情形。

类型、属性判断

分清楚typeof和instanceof的适用情形

  • 判断引用类型(比如Array和Date)时,不要用typeof,因为它返回总是object;应该用instanceof操作符,比如instanceof Array
  • instanceof不能跨帧使用,因为不同的帧的同名构造函数缺省为不同的构造函数,而typeof是可以跨域使用的。

in的妙用:

  • 检测某个DOM元素是否包含某个方法: if(“querySelctorAll” in document)
  • 跨帧该怎么检查是否是数组?(注意前面已经说过instanceof不能跨帧使用)使用Object.prototype.toString这个函数,或者使用ECMAScript5引入的Array.isArray()方法:
// 判断对象类型是否为数组
function isArray(val){
if(typeof Array.isArray === 'function'){
return Array.isArray(val);
} else {
return Object.prototype.toString.call(val) === '[object Array]';
}
}
  • 判断某个对象是否包含某个属性prop:不使用obj[‘prop’] == null/undefined,而是使用prop in obj(注意in会遍历原型链,如果只是判断是否是实例方法,则使用下面的hasOwnProperty方法)

hasOwnProperty是Object唯一不会遍历原型链的方法

  • 判断某个实例属性用hasOwnProperty,但是因为IE8及更早版本的DOM并非继承自Object,调用DOM的hasOwnProperty方法时应先做判断:
// obj为一般对象
if (obj.hasOwnProperty('prop')) {
;// ...
}
// obj为DOM对象
if('hasOwnProperty' in obj && obj.hasOwnProperty()) {
;// ...
}
变量提升

到目前为止javascript没有引入块语句作用域,所以有些块语句里声明的变量可能会带来语义上的混淆。因此好的实践是将函数作用域或者对象作用域内所有声明的变量按照隐式变量提升的方式显式放到代码的开头部分。

  • 第一句总是声明所有的局部变量
  • 合并成一个var声明语句,这样成本更低,代码更短,下载更快。
// 所有局部变量合成为一个var声明语句
var s1, s2, s3,
str1 = 'abcde',
obj = { 1:'abc', 'xx':'oo' };
==和===比较
  • 对象obj和数字做==比较时,会调用valueOf自动转换成数字进行比较,比如Boolean对象true和2比较 true==2返回false,因为true会首先转换成1
  • 字符串和数字比较时,字符串使用Number()转换成数字,比如”0×19″ == 25
  • javascript的==隐式转换比较混乱,推荐总是使用===和!==提高代码可读性和可维护性
临时包装对象的特性

给变量用内置类型的字面量赋值以后,每次使用这个变量会产生一个临时包装对象,但是这个包装对象是每次用后即弃的。

// 临时包装对象用后即弃
var str = "abc";
str.flag = true;
console.log(str.flag); // undefined

上面代码给str添加了一个flag属性并赋值为true,但是这个str临时包装对象赋完值立即弃掉了。因此下一句打印是打印不出这个属性的值的。如果使用new操作符来显式创建这个对象,结果还是一样的:

// 不好的写法:显式new一个内置类型包装对象
var str = new String("abc");
str.flag = true;
console.log(str.flag); // undefined

上面的代码可能对开发者产生疑惑,因为第一句貌似是给str赋值了一个String对象。因此,为了避免不必要的代码歧义,建议不要使用new来创建内置类型对象。

第二部分:编程实践

前端代码应该尽量避免html/css/javascript代码之间的依赖性,提高各自的独立性。

  • 避免使用css的express表达式:(因为浏览器会高频率的计算该表达式,严重影响性能。)
/* css里使用express表达式严重降低性能 */
.box {
width: expression(document.body.offsetWidth + 'px');
}
  • 不应在javascript代码中直接修改css样式,而是将所有css样式放在css文件中,并组织在类中,只在javascript代码中修改DOM的className属性,通过类的添加和删除来改变元素样式。
  • 避免0级DOM绑定(在html中直接给元素onxxx属性赋值): 1.可能onclick=”doSomething”的这个doSomething函数还没有加载,此时会报错或者点击没有响应; 2.加深了两个UI层(html和javascript)的耦合性,典型的紧耦合代码
  • 一个全兼容的事件绑定函数:
// 全兼容的事件绑定函数
function addListener(target, type, handler) {
if (target.addEventListener) {
target.addEventListener(type, handler, false);
} else if (target.attachEvent) { // IE
target.attachEvent('on' + type, handler);
} else {
target['on' + type] = handler;
}
}

不要去破坏别人的模块。这里推荐一个无破坏性的命名空间定义方式:

// 无破坏性的命名空间定义方式
var yourGlobal = {
namespace: function(ns) {
var parts = ns.split('.'),
object = this,
i, len;
for (i = 0, len = parts.length; i < len; i++) {
if (!object[parts[i]]) {
object[parts[i]] = {};
}
object = object[parts[i]];
}
return object;
}
}
  • 隔离应用逻辑:

下面的代码直接将处理放到了handle函数里,如果在没有点击的情况下想要调用它就麻烦了:

// 不好的写法
function handleClick(event) {
console.log(event.clientX, event.clientY);
}

将应用逻辑分离后的代码:

// 应用逻辑和事件处理隔离
function handleClick(event) {
logPosition(event);
}
function logPosition(event) {
console.log(event.clientX, event.clientY);
}

不要分发事件对象

上面的代码处理还是有问题,因为logPosition的参数带有应用逻辑不需要的信息,因此继续改进:

// 改进:避免分发事件对象
function handleClick(event) {
logPosition(event.clientX, event.clientY);
}
function logPosition(x, y) {
console.log(x, y);
}

对象的保护:Object的方法preventExtension、seal和freeze(保护强度递增)

// 对象的保护
'use strict'
// 不能增加属性
Object.preventExtension(cat);
console.log(Object.isExtensible(cat));
cat.age = 1; // error.
// 不能增删属性
Object.seal(cat);
console.log(Object.isExtensible(cat));
console.log(Object.isSealed(cat));
delete cat.name; // error.
cat.age = 1; // error.
// 不能增删改
Object.freeze(cat);
console.log(Object.isExtensible(cat));
console.log(Object.isSealed(cat));
console.log(Object.isFrozen(cat));
cat.name = "Kitty"; // error.
delete cat.name; // error.
cat.age = 1; // error.

注意:以上error如果不使用strict模式的话会被浏览器默默吞掉。

  • 尽量使用特性检测代替userAgent检测,比如if(document.getElementById()) { … } 而不是去判断用户代理if(navigator.userAgent.indexof(‘MSIE 7′) > -1);特性检测的优点在于不依赖于浏览器。

常用文件结构:

  • src, build, lib, doc, release, test (一般src和test里的文件名存在一一对应的关系)

原文地址:http://www.mrraindrop.com/2013/07/13/maintainable-javascript-notes/

编写可维护的Javascript纪要的更多相关文章

  1. 《编写可维护的JavaScript》之编程实践

    最近读完<编写可维护的JavaScript>,让我受益匪浅,它指明了编码过程中,需要注意的方方面面,在团队协作中特别有用,可维护性是一个非常大的话题,这本书是一个不错的起点. 本书虽短,却 ...

  2. 编写可维护的Javascript读书笔记

    写在前面:之前硬着头皮参加了java方面的编程规范培训,收货良多,工作半年有余的时候,总算感觉到一丝丝Coding之美,以及造轮子的乐趣,以至于后面开发新功能的时候,在Coding style方面花了 ...

  3. 《编写可维护的javascript》读书笔记(中)——编程实践

    上篇读书笔记系列之:<编写可维护的javascript>读书笔记(上) 上篇说的是编程风格,记录的都是最重要的点,不讲废话,写的比较简洁,而本篇将加入一些实例,因为那样比较容易说明问题. ...

  4. 《编写可维护的javascript》读书笔记(上)

    最近在读<编写可维护的javascript>这本书,为了加深记忆,简单做个笔记,同时也让没有读过的同学有一个大概的了解. 一.编程风格 程序是写给人读的,所以一个团队的编程风格要保持一致. ...

  5. 编写可维护的JavaScript 收纳架

    如果你看过Nicolas C.Zakas写过的任何作品,你必须承认他是个不折不扣的天才.也只有天才级的才能写出<JavaScript高级程序设计>让所有的前端攻城师人手一本.Nicolas ...

  6. 【读书笔记】读《编写可维护的JavaScript》 - 编程实践(第二部分)

    本书的第二个部分总结了有关编程实践相关的内容,每一个章节都非常不错,捡取了其中5个章节的内容.对大家组织高维护性的代码具有辅导作用. 5个章节如下—— 一.UI层的松耦合 二.避免使用全局变量 三.事 ...

  7. 编写可维护的JavaScript之编程风格

    在团队中只有每个人的编程风格一致,大家才能方便的互相看懂和维护对方的代码. 1. 层级缩进 对于层级缩进目前有两种主张:1)使用制表符这种方法有两种好处,第一,制表符和缩进层级之间是一一对应关系,符合 ...

  8. 《编写可维护的JavaScript》 笔记

    <编写可维护的JavaScript> 笔记 我的github iSAM2016 概述 本书的一开始介绍了大量的编码规范,并且给出了最佳和错误的范例,大部分在网上的编码规范看过,就不在赘述 ...

  9. 编写可维护的JavaScript代码(部分)

    平时使用的时VS来进行代码的书写,VS会自动的将代码格式化,所有写了这么久的JS代码,也没有注意到这些点.看了<编写可维护的javascript代码>之后,做了些笔记. var resul ...

随机推荐

  1. C#读写EXCEL(二) ZedGraph在Asp.net中的应用

      C#读写EXCEL(二) 2010-08-25 14:50:42|  分类: 默认分类 |  标签: |举报 |字号大中小 订阅 用微信  “扫一扫” 将文章分享到朋友圈. 用易信  “扫一扫” ...

  2. ubuntu下编译ffmpeg并用eclipse调试

    一.下载ffnpeg源码 下载地址:http://ffmpeg.org/download.html 二.解决版本问题 可能之前你编译过ffmpeg,或者装过相关的库,那都要先卸载掉,否则用的时候会报一 ...

  3. CBitmap Detach和DeleteObject的关系

    注意:当使用完资源后,必须通过调用函数以释放加速器表.位图.光标.图标以及菜单所占的内存资源:      加速器表:DesteoyAcceleratorTable:      位图:DeleteObj ...

  4. c#winform图片绘制与图片验证码

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  5. SSH免密登陆配置过程和原理解析

    SSH免密登陆配置过程和原理解析 SSH免密登陆配置过很多次,但是对它的认识只限于配置,对它认证的过程和基本的原理并没有什么认识,最近又看了一下,这里对学习的结果进行记录. 提纲: 1.SSH免密登陆 ...

  6. PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解

    使用Python进行数据分析,大家都会多少学习一本经典教材<利用Python进行数据分析>,书中作者使用了Ipython的交互环境进行了书中所有代码的案例演示,而书中的Ipython交互环 ...

  7. ora-24247 网络访问被访问控制列表ACL拒绝

    ,     upper_port  );   COMMIT; END; / --3.创建访问控制列表(ACL)network_services, BEGIN  DBMS_NETWORK_ACL_ADM ...

  8. Codeforces 1120D (树形DP 或 最小生成树)

    题意看这篇博客:https://blog.csdn.net/dreaming__ldx/article/details/88418543 思路看这篇:https://blog.csdn.net/cor ...

  9. Tensorflow学习(练习)—下载骨骼图像识别网络inception数据集

    import tensorflow as tfimport osimport tarfileimport requests #inception模型下载地址inception_pretrain_mod ...

  10. mybatis 框架 的简单使用

    # Global logging configuration #在开发环境下日志级别要设置成DEBUG,生产环境设置成info或error log4j.rootLogger=DEBUG, stdout ...