第一部分: 编程风格

在大型项目开发中,因为项目可读性规范性的需要(就像《编写可维护性的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. Listview使用安卓自带布局实现单选

    安卓提供了一些自带的布局,使用非常简单.直接看代码吧. package com.example.linfeng.myapplication; import android.app.Activity; ...

  2. USACO2.1.3 三值排序

      Description 排序是一种很频繁的计算任务.现在考虑最多只有三值的排序问题.一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌序的时候. 在这个任务中可能的值只有三种1,2和3.我们用交 ...

  3. 你是真的了解ssh吗 说说你不知道的ssh

    Ssh命令——基石天赋 主要参数说明: -l 指定登入用户 -p 设置端口号 -f 后台运行,并推荐加上 -n 参数 -n 将标准输入重定向到 /dev/null,防止读取标准输入 -N 不执行远程命 ...

  4. Eclipse 控制台不显示打印信息的处理方法

    1.进windows菜单 -> show view -> console2.还是windows菜单里面 -> preferences -> 打开左边的run/debug -&g ...

  5. oracle使用PLSQL免安装客户端

    2. 下载Oracle Instant Client (32-bit) 只需要下载instantclient-basic-nt-11.2.0.3.0.zip就可以了,其它的都是一些根据不同需要扩展的包 ...

  6. oracle数据库单表查询

    今天给大家分享的是关于数据库的单表查询,像单表查询/多表查询/分组查询/子查询,这些方法的使用在实际项目过程中会经常用到,作为一名合格的测试人员如果不会数据库那肯定是不行的,行走江湖可能随时会面临被侮 ...

  7. eWebEditor9.x整合教程-Xproer.WordPaster

    版权所有 2009-2017 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webplug/wordpa ...

  8. datagrid 自定义 pager

    $(document).ready(function(){ var p = $('.easyui-datagrid').datagrid('getPager'); $(p).pagination({ ...

  9. 学习如何用VS2010创建ocx控件

    1参考文章 (1)这一篇将使用vc创建ocx控件:http://blog.csdn.net/jiadelin/article/details/2917225 (2)这一篇文章有关vs2010创建act ...

  10. MongoDB整理笔记のGUI操作

    值得幸运的是,其实MongoDB也有像类似于PL/SQL一样的界面操作工具操作MongoDB. 下面就来介绍几款不同的界面工具,大家各取所需! MongoVUE 主页:http://www.mongo ...