JavaScript数据存取的性能问题

时间:2021-01-31 21:00:47

JavaScript中四种基本的数据存取位置

  字面量:只代表自身 字符串、数字、布尔值、对象、函数、数组、正则,以及null和undefined    快

  本地变量:var定义的    快

  数组元素:以数字作为索引   慢

  对象成员:以字符串作为索引    慢

  大多数情况下,从字面量和一个局部变量中存取数据的性能差异不大,而访问数组元素和对象成员的代价略高(根据地址查找堆)

一、作用域链和标识符解析

  函数内部属性[[scope]]包含了被创建时所在作用域中的对象的集合,称为函数的作用域链

function add(num1, num2){
var sum = num1 + num2;
return sum;
}

  若add是在全局环境下创建,那它的作用域链,就只有一个全局对象(this:window, window:object, document:object, add:function)

var total = add(5, 10);

  当add执行时,其执行环境的作用域链为 活动对象(this:window, arguments:[5, 10], num1:5, num2: 10, sum:undefined) +  上面的全局对象

  标识符解析时,查找执行环境作用域链,找到即停。标识符所在的位置越深,读写速度就越慢。全局变量总是在执行环境作用域链的最末端,因此它也是最远的

  如果每个某个跨作用域的值在函数中被引用了一次以上,建议把它存储到局部变量。如下:

var bd = document.body,
links = document.getElementsByTagName('a'),
goBtn = document.getElementById('go-btn');

  document是个全局变量,仅仅声明变量就被访问了这么多次,但每一次访问document都要遍历整个作用域链,直到最后在全局变量对象中找到,开销很大,建议用局部变量存储:

var doc = document,
bd = doc.body,
links = doc.getElementsByTagName('a'),
goBtn = doc.getElementById('go-btn');

二、对象成员和原型链

对象中有两种成员类型:实例成员 和 原型成员。实例成员直接存在于对象实例中,原型成员则从对象原型中继承而来。

var obj = {},
var arr = [];
function fun(){
//do something
}

  obj的原型链:obj ---> Object.prototype

  arr的原型链:arr ---> Array.prototype --->Object.prototype

  fun的原型链:fun ---> Function.prototype ---> Object.prototype

所有对象都是Object的实例,所以都会继承Object.prototype中的方法,如:hasOwnProperty、isPropertyOf、toString

arr调用toString时,要一级一级搜索原型链,直到Object.prototype。可见存在的位置越深,寻找就越慢。

搜索对象成员本身就比 从字面量或局部变量中读取数据 代价高,再加上遍历原型链,更慢。

若要多次读取同一个对象属性,最佳做法是将属性值保存到局部变量中,避免多次查找带来的性能开销