第一部分: 编程风格

在大型项目开发中,因为项目可读性规范性的需要(就像《编写可维护性的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. 解决The JSP specification requires that an attribute name is preceded by whitespace问题

    笔者今天调试界面出现下边这个问题: The JSP specification requires that an attribute name is preceded by whitespace 经查 ...

  2. IDEA中快速排除maven依赖

    选中该模块 点击show dependenties 切换试图 选中要排除的依赖,右击 选择Execlude,然后选择需要在哪个模块添加排除依赖 完成

  3. c盘不能新建文件的解决办法

    来自为知笔记(Wiz) 附件列表

  4. java实现 数组中两个元素相加等于指定数的所有组合

      package com.algorithm.hash; public class alg1 { public static void main(String argv[]) { int[] arr ...

  5. java基础之io流总结一:io流概述

    IO流概念: 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.io流是实现输入和输出的基础,可以方便的实现数据的输入和输出操作. IO流的分类: 根据处理数据类型的不同分为:字符流 ...

  6. IIS设置Access-Control-Allow-Origin

    打开iis,找到“HTTP响应标头”点进去, 在右侧可以看到添加,然后添加如下标头即可Access-Control-Allow-Headers:Content-Type, api_key, Autho ...

  7. Nginx配置之基于域名的虚拟主机

    1.配置好DNS解析 大家好,今天我给大家讲解下在Linux系统下DNS服务器的基本架设,正向解析,反向解析,负载均衡,还有从域以及一个服务器两个域或者多个域的情况. 实验环境介绍:1.RHEL5.1 ...

  8. codeforce452DIV2——E. Segments Removal

    题目 Vasya has an array of integers of length n. Vasya performs the following operations on the array: ...

  9. window7 和ubuntu 双系统时 ubuntu不能引导怎么办?

    假如你的Ubuntu的 / 分区是sda9,又假如 /boot分区是 sda6,在终端下输入sudo -imount /dev/sda7 /mntmount /dev/sda6 /mnt/boot ( ...

  10. the install of mysql in Linux System

    一.下载MySql 浏览器打开 https://www.mysql.com/downloads/mysql/#downloads 下载 我下载的版本是Red Hat 5 版本的 https://www ...