Skip to main content

28.2.1作用域意识

作用域意识

随着作用域链中作用域数量的增加,访问当前作用域外部变量所需的时间也会增加。 访问全局变量始终比访问局部变量慢,因为必须遍历作用域链。任何可以缩短遍历作用域链时间的举措都能提升代码性能。

避免全局查找

全局变量和函数相比于局部值始终是 最费时间的,因为需要经历作用域链查找。来看下面的函数:

function updateUI() {
// 1次
let imgs = document.getElementsByTagName("img");
for (let i = 0, len = imgs.length; i < len; i++) {
//2次
imgs[i].title = "${document.title} image ${i}";
}
// 3次
let msg = document.getElementById("msg");
msg.innerHTML = "Update complete.";
}

这个函数看起来好像没什么问题,但其中三个地方引用了全局 document 对象。如果页面的图片非 常多,那么 for 循环中就需要引用 document 几十甚至上百次,每次都要遍历一次作用域链。

通过在局部作用域中保存 document 对象的引用,能够明显提升这个函数的性能,因为只需要作用域链查找。

通过创建一个指向 document 对象的局部变量,可以通过将全局查找的数量限制为一个来提高这个函数 的性能:

function updateUI() {
// 指向局部变量
let doc = document;
let imgs = doc.getElementsByTagName("img");
for (let i = 0, len = imgs.length; i < len; i++) {
imgs[i].title = "${doc.title} image ${i}";
}
let msg = doc.getElementById("msg");
msg.innerHTML = "Update complete.";
}

这里先把 document 对象保存在局部变量 doc 中。然后用 doc 替代了代码中所有的 document。 这样调用这个函数只会查找一次作用域链,相对上一个版本,肯定会快很多。

因此,一个经验规则就是,只要函数中有引用超过两次的全局对象,就应该把这个对象保存为一个 局部变量。

不使用 with 语句

选择正确的方法

避免不必要的属性查找

表 示 法 名 称 说 明
O(1) 常量 无论多少值,执行时间都不变。表示简单值和保存在变量中的值
O(logn) 对数 执行时间随着值的增加而增加,但算法完成不需要读取每个值。例子:二分查找
O(n) 线性 执行时间与值的数量直接相关。例子:迭代数组的所有元素
O(n2
) 二次方 执行时间随着值的增加而增加,而且每个值至少要读取 n 次。例子:插入排序