24. 最佳实践

24.1 可维护性

在早期的网站中,JavaScript主要用于小特效或者表单验证。

  • 命名约定
    • 变量名应为名词 car, people
    • 函数名以动词开头,如getName()。 返回布尔值则以is-开头,如isEnable()
  • 变量类型透明
    • 初始化,在定义一个变量过后,初始化一个值,来暗示他将来应该如何应用。
      • var found = false;
    • 匈牙利标记法,变量名前加一个或多个字符表示数据类型
      • o对象 s字符串 i整数 f浮点数 b布尔值
      • var bFound = false;
    • 类型注释
      • var found /*:Boolean*/ = false;(有点TypeScript的感觉)
  • 松散耦合
    • HTML和JavaScript各自代表解决方案中的不同层次: HTML 是数据, JavaScript 是行为
    • 勿将event对象传给其他方法,只传event对象中所需的数据
    • 任何可以在应用层面的动作都应该可以在不执行任何事件处理程序的情况下进行
    • 任何事件处理程序都应该处理事件,然后将处理权转交给应用逻辑
  • 尊重对象所有权
    • 不要修改不是你创建的对象
  • 避免使用全局变量
    • 使用命名空间
  • 避免与null比较
    • 基本类型 typeof
    • 引用类型 instanceof

24.2 性能

  • 注意作用域
    • 避免全局查找
    • 将在一个函数中会用到多次的全局对象存储为局部变量
// 避免全局查找
function updateUI(){
	var imgs = document.getElementsByTagName("img");
	for(let i = 0; i < imgs.length; i ++){
		imgs[i].title = document.title + "img" + i; // 这里要通过作用域链查找document很多次
	}
}
将多次引用的全局变量存储为局部变量
function updateUI(){
	var doc = document;// 只查找document一次,查到后缓存起来
	var imgs = document.getelementsByTagName("img");
	for(let i =0 ; i < img.length; i++){
		imgs[i].title = doc.title + "img" + i;
	}
}
  • 使用变量数组要比访问对象上的属性更有效率
    • 对象上的任何属性查找都比访问变量和数组花费更长时间,因为必须在原型链上对拥有该名称的属性进行一次搜索
    • 一旦多次用到对象属性,就应该将其存储在局部变量中,第一次访问该值是O(n),以后都是O(1)
    • 尽可能多的使用局部变量将属性查找替换为值查找
  • 优化循环
    • 减值迭代
    • 简化终止条件(使用值,而非属性查找)
    • 简化循环体
    • 使用后测试循环do-while
  • 展开循环
    • Duff device 处理大数据集
    • 计算迭代次数是否为8的倍数,将一个循环展开成一系列语句
  • 避免双重解释
    • 当JavaScript想解析JavaScript的时候就会存在双重解释惩罚
    • 在JavaScript代码运行的同时必须重新启动一个解析器来解析新的代码,而实例化一个解析器是不容忽视的开销。
// 避免
eval("alert('Hello')");
var sayHi = new Function("alert('Hello')");
setTimeout("alert('Hello')", 1000);
// 修正后
alert("Hello");
var sayHi = function(){
	alert("Hello");
}
setTimeout(sayHi, 1000);
  • 其他
    • 原生方法快
    • switchif-else
    • 位运算符快
  • 最小化语句数
    • 多个变量一起声明
    • 插入迭代值
    • 使用字面量,而不是对象构造函数
var a = 0,b = 'a',c = true,d = {foo: 'bar'}; // 多变量一起声明
var names = values[i++]; // 合并迭代
  • DOM更新
    • 最小化现场更新
      • 利用documentFragment
      • 使用innerHTML
    • 事件委托(代理)
    • 最小化访问HTMLCollection的次数

24.3 部署

你写的代码不应该原封不动地放入浏览器中,理由如下:

  1. 知识产权问题————带有完整注释的代码放到线上,别人看得懂,会有安全问题
  2. 文件大小————书写代码要保证容易阅读,但这对于性能是不利的。浏览器并不能从额外的空白字符或者冗长的变量名和函数名中获得什么好处
  3. 代码组织
  • 将代码分离成多个文件只是提高可维护性,并非为了部署;要进行部署的时候,需要将这些源代码合并成一个或几个归并文件。
  • 推荐Web应用中尽可能使用最少的JavaScript文件,是因为HTTP请求是web性能瓶颈之一。
  • JavaScript文件压缩:代码长度和配重Wire Weight
    • JavaScript并非编译为字节码,而是按照源代码传送的,代码文件中包含浏览器执行所不需要的信息和格式
    • 注释、额外的空白,以及长长的变量名和函数名,对于浏览器来说是不必要的
    • 所以压缩工具做三件事:1.删除额外空白;2.删除注释;3.缩短变量名;
  • 配重指的是实际从服务器传送到浏览器的字节数。
    • Content-encoding: gzip