共计 5096 个字符,预计需要花费 13 分钟才能阅读完成。
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、注意 HTMLCollection
3、部署
3.1 构建过程
3.2 验证
3.3 压缩
4、小结