1、可维护性1.1 可维护代码特征可理解性直观性可适应性可扩展性可调试性1.2 代码约定1、可读性(代码缩进和代码注释)2、变量和函数命名变量名应该为名词函数名应该以动词开始变量和函数都应使用合乎逻辑的名字,不要担心长度。3、变量类型透明(1)第一种方式是初始化,初始化为一个特定的数据类型可以很好的指明变量的类型;//通过初始化指定变量类型var found = false; //布尔型var count = -1; //数字var name = “”; //字符串var person = null; //对象缺点在于无法用于函数声明中函数参数。(2)第二种方式是使用匈牙利标记法来指定变量的类型。匈牙利标记法在变量名之前加上一个或多个字符来表示数据类型。//用于指定数据类型的匈牙利标记法var bFound = false; //布尔型var iCount = -1; //数字var sName = “”; //字符串var oPerson = null; //对象缺点在于让代码某种程度上难以阅读,阻碍了没有用它是代码的直观性和句子式的特征。(3)第三种方式是使用类型注释。//用于指定类型的类型注释var found /:Boolean/ = false; var count /:int/ = -1; var name /:String/ = “”; var person /:Object/ = null; 缺点在于不能用多行注释一次注释大块的代码。(在每一行上使用单行注释可解决这个问题)1.3 松散耦合只要应用的某个部分过于依赖另一部分,代码就是耦合过紧,难以维护。1、解耦HTML/JavaScript2、解耦CSS/JavaScript3、解耦应用逻辑/事件处理程序应用和业务逻辑之间松散耦合的几条原则:勿将event对象传给其他方法;只传来自event对象中所需的数据;任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行;任何事件处理程序都应该处理事件,然后将处理转交给应用逻辑。1.4 编程实践1、尊重对象所有权不要为实例或原型添加属性;不要为实例或原型添加方法;不要重定义已存在的方法;可以通过以下方式为对象创建新的功能创建包含所需功能的新对象,并用它与相关对象进行交互;创建自定义类型,继承需要进行修改的类型,然后可以为自定义类型添加额外功能;2、避免全局量最多创建一个全局变量,让其他对象和函数存在其中。var MyApplication = { name : “Nicholas”, sayName : function(){ alert(this.name); }};命名空间包括创建一个用于放置功能的对象。唯一的全局变量作为一个容器,其中定义了其他方法,用这种方式将功能组合在一起的对象,叫做命名空间。命名空间有助于确保代码可以在同一页面上与其他代码以无害的方式一起工作。3、避免与null进行比较直接将值与null比较是使用过度的,并且常常由于不充分的类型检查导致错误。如果看到了与null比较的代码,尝试使用一下技术替换:如果值应为一个引用类型,使用instanceof操作符检查其构造函数;如果值应为一个基本类型,使用typeof检查其类型;如果是希望对象包含某个特定的方法名,则使用typeof操作符确保指定名字的方法存在于对象上。4、使用常量将数据从应用逻辑分离出来的思想。可以在不冒引入错误的风险的同时,就改变数据。如下例function validate(value) { if(!value) { alert(“Invalid value”); location.href = “/errors(invalid.php)”; }}可以通过将数据抽取出来变成单独定义的常量的方式,将应用逻辑与数据修改隔离开来。修改如下:var Constants = { INVALID_VALUE_MSG: “Invalid value”, INVALID_VALUE_URL: “/errors/invalid.php” };function validate(value) { if(!value) { alert(Constant.INVALID_VALUE_MSG); location.href = COnstant.INVALID_VALUE_URL; }}关键在于将数据和使用它的逻辑进行分离。需要提取作为常量的值大致有以下几种情况:重复值:任何在多处用到的值都应抽取为一个常量;用户界面字符串:任何用于显示给用户的字符串,都应该被抽取出来以方便国际化;URLs:在WEB应用中,资源位置很容易变更,所以推荐用一个公共地方存放所有的URL;任意可能会更改的值2、性能2.1 注意作用域访问全局变量总是比访问局部变量慢。只要能减少花费在作用域上的时间,就能增加脚本的整体性能。1、避免全局查找function updateUI() { var imgs = document.getElementsByTagName(“img”); for(var i=0, len=imgs.length; i<len; i++) { imgs[i].title = document.title + “image” + i; } var msg = document.getElementsById(“msg”); msg.innerHTML = “Update complete."}上述函数看起来完全正常,但是它包含了三个对于全局document对象的引用。通过创建一个指向document对象的局部变量,就可以通过限制一次全局查找来改进这个函数的性能。改进后的代码如下:function updateUI() { var doc = document; var imgs = doc.getElementsByTagName(“img”); for(var i=0, len=imgs.length; i<len; i++) { imgs[i].title = doc.title + “image” + i; } var msg = doc.getElementsById(“msg”); msg.innerHTML = “Update complete."}2、避免with语句with语句会创建自己的作用域,因此会增加其中执行的代码的作用域的长度。大多数情况下,可以是同局部变量完成相同的事情而不引入新的作用域。function updateBody() { with(document.body) { alert(tagName); innerHTML = “Hello World!”; }}以上代码中的with语句让document.body变得更容易使用,但是其实可以使用局部变量达到相同的效果。function updateBody() { var body = document.body; alert(body.tagName); body.innerHTML = “Hello World!”;}2.2 选择正确的方法1、避免不必要的属性查找一旦多次用到属性对象,应该将其存储在局部变量中。一般来讲,只要能减少算法的复杂度,就要尽可能减少。尽可能多的使用局部变量将属性查找替换为值查找。进一步讲,如果既可以用数字化的数组位置进行访问,也可以使用命名属性,那么使用数字位置。2、优化循环(1)减值迭代:很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。(2)简化终止条件(3)简化循环体:确保没有某些可以被很容易移出循环的密集操作。(4)使用后测循环:最常使用的for循环和while循环都是前测试循环。而如do-while这种后测试循环,可以避免最终终止条件的计算,因此运行更快。3、展开循环(可以考虑一种叫做Duff装置的技术)当循环次数是确定的,消除循环并使用多次函数调用往往更快。如下循环代码for(var i=0; i<values.length; i++) { process(values[i]);}可以改为process(values[0]);process(values[1]);process(values[2]);//Duff装置的基本概念是通过计算迭代的次数是否为8的倍数将一个循环展开为一系列语句。var iterations = Math.ceil(values.length / 8);var startAt = values.length % 8;var i = 0;do{ switch(startAt) { case 0: process(value[i++]); case 7: process(value[i++]); case 6: process(value[i++]); case 5: process(value[i++]); case 4: process(value[i++]); case 3: process(value[i++]); case 2: process(value[i++]); case 1: process(value[i++]); } startAt = 0;}while(–iterations > 0);Math.ceil()函数返回大于或等于一个给定数字的最小整数Math.floor()函数返回小于或等于一个给定数字的最大整数DUff装置的实现是通过将values数组中的元素个数除以8来计算出循环需要进行多少次迭代的。然后使用取整的上限函数确保结果是整数。如果完全根据8来进行迭代,可能会有一些不能被处理到的元素,这个数量保存在startAt变量中。首次执行该循环时,会检查startAt变量看有需要多少次额外调用。那么最开始的时候process()则只会被调用2次。在接下来的循环中,startAt被重置为0,这样之后的每次循环都会调用8次process()。展开循环可以提升大数据及的处理速度。4、避免双重解释//某些代码求值——避免!!eval(“alert(‘Hello World!’)”);//创建新函数——避免!!var sayHi = new Function(“alert(‘Hello World!’)”);//设置超时——避免!!setTimeout(“alert(‘Hello World!’)",500);修改为//某些代码求值——已修正alert(‘Hello World!’);//创建新函数——已修正var sayHi = function(){ alert(‘Hello World!’)};//设置超时——已修正setTimeout(function(){ alert(‘Hello World!’);},500);5、性能其他的注意事项原生方法比较快;Switch语句较快;位运算符比较快2.3 最小化语句数完成多个操作的单个语句要比完成单个操作的多个语句快。1、多个变量的声明//4个语句——浪费!var count = 5;var color = “blue”;var values = [1,2,3];var now = new Date();修改为var count = 5; color = “blue”; values = [1,2,3]; now = new Date();2、插入迭代值当使用迭代值(也就是在不同的位置进行增加或者减少的值)的时候,尽可能使用合并语句。var name = values[i]; i++;例如以上代码修改为var name = values[i++];3、使用数组和对象字面量创建数组和对象的方法有两种:使用构造函数或者是字面量。使用构造函数总是要用到更过的语句来插入元素或者定义属性,而字面量可以将这些操作在一个语句中完成。//用4个语句创建和初始化数组——浪费 var values = new Array();values[0] = 123;values[1] = 456;values[2] = 789;//只用一条语句创建和初始化数组var values = [123, 456, 789];只要有可能,尽量使用数组和对象的字面量表达方式来消除不必要的语句。2.4 优化DOM交互1、最小化现场更新之所以叫现场更新,是因为需要立即(现场)对页面对用户的显示进行更新。一旦需要更新DOM,请考虑使用文档片段来构建DOM结构,然后再将其添加到现存的文档中。2、使用innerHTML对于大的DOM更改,使用innerHTML要比使用标准DOM方法创建同样的DOM结构快得多。使用innerHTML的关键在于最小化调用它的次数。3、使用事件代理任何可以冒泡的事件都不仅仅可以在事件目标上进行处理,目标的任何祖先节点上也能处理。使用这个只是就可以将事件处理程序附加到更高层的地方负责多个目标的事件处理。4、注意HTMLCollection3、部署3.1 构建过程3.2 验证3.3 压缩4、小结