最佳实践将分为三大方面讲述:1.可维护性、2.性能、3.部署
参考《JavaScript高级程序设计》总结出以下内容:
1.可维护性
1.1什么是可维护的代码?
可维护的代码遵循以下特点:
- 可理解性:其他人可以接手代码并理解它的意图和一般途径,而无需开发人员的完整解释。
- 直观性:代码中的东西一看就能明白,不管其操作过程多么复杂。
- 可适应性:代码以一种数据上的变化不要求完全重写的方法撰写。
- 可拓展性:在代码架构上已考虑到在未来允许对核心功能进行扩展。
- 可调试性:当有地方出错时,代码可以给予你足够的信息来尽可能直接的确定问题所在。
1.2 代码约定
1.可读性:可维护的前提是必须可读,所以可读性是很重要的,主要两方面改善可读性:缩进,注释。
一般而言以下地方需要进行注释:
1、函数和方法
2、大段代码
3、复杂的算法
4、Hack
2.变量和函数命名
适当给变量和函数起名字对于增加代码可理解性和可维护性是非常重要的。
命名规则如下:
- 变量名应为名词如car或person
- 函数名应该以动次开始,如getName()。返回布尔类型值的函数一般以is开头,如isEnable()。
- 变量和函数都应使用合乎逻辑的名字,不要担心长度。长度问题可以通过后处理和压缩来缓解。
3.变量类型透明
JavaScript中变量类型是松散类型的,所以很容易就忘记变量所应包含的数据类型。合适的命名方式可以一定程度上缓解这个问题,但放到所有的情况下看,还不够。有三种表示变量数据类型的方式。
第一种方式是初始化。当定义了一个变量后,他应该被初始化为一个值,来暗示他将来应该如何应用,例如:
var found = false; //布尔型
var count = -1; //数字
var name = ''; //字符串
var person= null; //对象初始化为一个特定的数据类型可以很好的指明变量的类型,但缺点是他无法用于函数声明中的参数。
第二种方法是使用匈牙利标记法来指定变量类型。例如:
var bFound; //布尔型
var iCount; //整数
var sName; //字符串
var oPerson; //对象最后一种方法是使用类型注释。类型注释放在变量名右边。如下所示:
var found /*:Boolean*/ = false;
var count /*:int*/ = 10;
var name /*:String*/ = 'nicholas';
var person /*:Object*/ = null;缺点是不能用多行注释一次注释大块的代码。
1.3 松散耦合
只要应用的某个部分过分依赖于另一部分,代码就是耦合过紧,男与维护。典型的问题如:对象直接引用另一个对象,并且当修改其中一个的同时需要修改另外一个。紧密耦合的软件难于维护并且需要经常重写。
1.解耦HTML/JavaScript
尽量避免的紧密耦合情况:
1、直接写在HTML中的JavaScript
2、使用事件处理程序属性值的紧密耦合的HTML/javascript
3、在JavaScript中创建大量HTML。
理想的情况是,HTL和JavaScript应该完全分离,并且通过外部文件和使用DOM附加行为来包含JavaScript。
2.解耦CSS/JavaScript
现代Web开发免不了要用JavaScript改变某些样式,但是将来如果需要更改样式表,CSS和JavaScript文件可能都需要更改。这会对开发人员造成心理阴影...所以在这两个层次之间必须有清晰的划分。
但也是有解决方法的:通过更改样式类而非特定样式。
3.解耦应用逻辑/事件处理程序
1.4 编程实践
1.尊重对象所有权
意思是你不能修改不属于你的对象。更具体的说:
- 不要为实例或原型添加属性;
- 不要为实例或原型添加方法;
- 不要重定义已存在的方法。
只要对象不是自己创建的,就永远不去修改,明显Array、document这些对象都不是你的,它们在你的代码执行前就存在了。但是依然可以通过以下方式为对象创建新的功能:
- 创建包含所需功能的新对象,并用它与相关对象进行交互;
- 创建自定义类型,继承需要进行修改的类型,然后可以为自定义类型添加额外功能。
2.避免全局变量
3.避免与null进行比较
4.使用常量
尽管JavaScript没有常量的正是概念,但它还是很有用的。这种将数据从应用逻辑分离出来的思想,可以在不冒引入错误的风险的同时,就改变数据。请看以下例子:
function validata(value){
if(!value){
alert('Invalid value!');
location.href = '/errors/invalid.php';
]
}这个函数中有两段数据:要显示给用户的信息以及URL。显示在用户界面上的字符串应该以允许进行语言国际化的方式抽取出来。URL也应该被抽取出来,因为它们有随着应用成长而改变的倾向。 基本上,有着可能由于这样那样原因会变化的这些数据,那么都会需要找到函数并在其中修改代码。而每次修改应用逻辑的代码,都可能会引入错误。可以通过将数据抽取出来变成单独定义的常量的方式,将应用逻辑与数据修改隔离开来。例如:
var Constants = {
INVALID_VALUE_MSG: 'Invalid value!',
INVALID_VALUE_URL: '/errors/invalid.php'
};
function validata(value){
if (!value){
alert(Constants.INVALID_VALUE_MSG);
location.href = Constants.INVALID_VALUE_URL;
}
};在这段重写过的代码中,消息和URL都被定义于Constants对象中,然后函数引用这些值。这些设置允许数据在无需使用它的函数的情况下进行变更。Constants对象甚至可以在完全独立的文件中定义,同时该文件可以由包含正确值的其他过程根据国际化设置来生成。
关键在于将数据和使用它的逻辑进行分离。要注意的值的类型如下所示。
重复值:任何在多出用到的值都应该抽取为一个常量,这就限制了当一个值变了而另一个没变的时候会造成的错误。这也包含了CSS类名。
用户界面字符串:任何用户显示给用户的字符串,都应被抽取出来以方便国际化。
URLs:在Web应用中,资源位置很容易变更,所以推荐一个公共地方存放所有的URL。
任意可能会更改的值:每当你在用到字面量值的时候,你都要问一下自己这个值在未来是不是会变化。如果答案是‘是’,那么这个值就应该被提取出来作为一个常量。
对于企业级的JavaScript开发而言,使用常量是非常重要的技巧,因为他能让代码更容易维护,并且在数据更改的同时保护代码。
2.性能
2.1 注意作用域
只要能减少化肥在作用域链上的事件,就能增加脚本的整体性能。
1.避免全局查找
2.避免with语句
2.2 选择正确方法
1.避免不必要的属性查找。
属性查找越多,执行时间就越长。
一般来讲,只要能减少算法的复杂度,就要尽可能减少。尽可能多地使用局部变量将属性查找替换为值查找。
2.优化循环
循环的基本优化步骤如下所示:
- 减值迭代:大多数循环使用一个从0开始、增加到某个特定值的迭代器。在很多情况ixa、从最大值开始,在循环中不断减值的迭代器更加高效。
- 简化终止条件:由于每次循环过程都会计算终止条件,所以必须保证它尽可能快。也就是说避免属性查找或其他O(n)的操作。
- 简化循环体:循环体是执行最多的,所以要确保其被最大限度的有话啊。确保没有某些可以被很容易移出循环的密集计算。
- 使用后测试循环:do-while
3.展开循环
当循环的次数是确定的,消除循环并使用多次函数调用往往更快。
针对大数据集使用展开循环可以节省很多时间,但对于小数据集,额外的开销则可能得不偿失。它是要花更多的代码来完成同样的任务,如果处理的不是大数据集,一般来说并不值得。
4.避免双重解释
5.性能的其他注意事项
- 原生方法较快:只要有可能,使用原生方法而不是自己用JavaScript重写一个。
- switch语句较快:如果有一系列复杂的if-else语句,可以转换成单个switch语句则可以得到更快的代码。 还可以通过将case语句按照最可能的到最不可能的顺序进行组织,来进一步优化switch语句。
- 位运算符较快
2.3 最小化语句数
JavaScript代码中的语句数量也影响所执行的操作的速度。完成多个操作的单个语句要比完成单个操作的多个语句快。所以就要找出可以组合在一起的语句,以减少脚本整体的执行时间。
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;
//用4个语句创建和初始化对象 - 浪费
var person = new Object*(;
person.name = 'nicholas';
person.age = 29;
person.sayName = function(){
alert(this.name);
};重写:
//只用一条语句创建和初始化数据
var values = [123,456,789];
//只用一条语句创建和初始化对象
var person = {
name : 'nicholas',
age : 29,
sayName : function(){
alert(this.name);
}
};只要有可能,尽量使用数组和对象的字面量表达方式来消除不要的语句。
2.4 优化DOM交互
在JavaScript的各方面中,DOM毫无疑问是最慢的一部分。
所以优化DOM交互是极其重要的,下面是关于DOM优化的总结:
1.最小化现场更新:尽量一次性把DOM元素添加成功,添加的操作(现场更新)越少越好。
2.使用innerHTML:innerHTML方法会在后台创建一个HTML解析器,然后使用内部的DOM调用来创建DOM,而非基于JavaScript的DOM调用。由于内部方法是编译好的而非解释执行的,所以执行快得多。
3.使用事件代理
4.注意HTMLCollection:最小化访问HTMLCollection的次数可以极大地改进脚本的性能。例如:
var images = document.getElementsByTagName('img'),
i,len;
for(i=0,len=images.length;i<len;i++){
//处理
}这里的关键在于长度length存入了len变量,而不是每次都去访问HTMLCollection的length属性,当在循环中使用HTMLCollection的时候,下一步应该是获取要使用的项目的引用,如下所示,一边避免在循环体内多次调用HTMLCollection。
var images = document.getElementsByTagName('img'),
image,
i,len;
for(i=0,len=images,length;i<len;i++){
image = images[i];
//处理
}这段代码添加了image变量,保存了当前的图像,这之后在循环内疚没有理由在访问images的HTMLCollection了。
发生以下情况时会返回HTMLCollection对象:
- 进行了对getElementsByTagName()的调用;
- 获取了元素的childNodes属性;
- 获取了元素的attributes属性;
- 访问了特殊的集合,如document.forms/document.images等。
以上。