【高性能JavaScript】读书笔记

来源:互联网 发布:彩虹六号推荐 知乎 编辑:程序博客网 时间:2024/05/31 13:14

【简介】对象因其数据类型的缘故,天生比其他数据类型存取慢,这一点我们无法改变,所以对于对象成员的优化,着重在减少重复调用和将对象成员缓存到局部变量中。

对象成员(Object Members)

1. 原型(Prototypes)

JavaScript中的对象是基于原型的,这一概念完全不同于传统面向对象编程语言中「类」的概念,「类」定义了创建新对象的过程,「原型」对象则为所有对象实例所共享。

对象通过一个内部属性(_ _ proto _ _)绑定到它的原型。因此,对象可以有两种成员类型:实例成员(也称「own成员」)和原型成员。实例成员直接存储在对象实例中,而原型成员则从对象原型继承而来。

var person = {    name: "Tom",    age: 23};alert(person.toString());

对于 person 对象,有两个实例成员:name 和 age;而下面调用的 toString() 方法,则是从原型对象中继承过来的。

person 对象的实例成员和原型成员我们可以用下面这个图来表示:
这里写图片描述

在开发的时候,我们可以通过 hasOwnProperty() 方法来判断对象是否包含某个实例成员:

// hasOwnProperty() 判断对象是否包含特定的实例成员(包括成员变量和成员方法)// 不包括原型成员console.log(person.hasOwnProperty("name")); // trueconsole.log(person.hasOwnProperty("toString")); // false

而通过 in 操作符,我们可以判断对象是否包含特定的属性(包括实例属性和原型属性):

// in 判断成员是否在对象中 // 包括实例成员和原型成员console.log("name" in person); // trueconsole.log("toString" in person); // true

2. 原型链(Prototype Chains)

对象的原型决定了实例的类型。我们可以使用 instanceof 操作符来检测某个对象是否是另一个对象的实例对象,从而探索原型链。

function Person(name, age) {    this.name = name;    this.age = age;}Person.prototype.sayName = function() {    alert(this.name);};var person = new Person("Tom", 23);// 判断person对象是否是 Person 和 Object 的实例对象console.log(person instanceof Person); // trueconsole.log(person instanceof Object); // trueperson.sayName();person.toString();

使用构造函数 Person 来创建一个新的 Person 实例,所以 person 的原型 _ _ proto_ _ 是 Person.prototype,而「Person.prototype」 的原型 _ _ proto_ _ 是 Object。所以,person 的原型链为 person -> Peroson -> Obejct。其中 sayName() 方法在 Person 中, toString() 方法在 Object 中。自然,原型链也和作用域链一样,方法在原型链中的位置越深,找到它就越慢,所带来的性能的消耗就越大。

总结一下原型链所带来的性能的问题,这个问题来自两方面。一个是搜索实例成员会比从字面量或局部变量中读取数据代价更高,另一个则是遍历原型链所带来的开销。

3. 缓存对象成员值(Caching Object Member Values)

无论是原型还是原型链,所带来的性能问题,都与对象成员有关,所以我们的优化思路就是减少使用对象成员。如果在一个函数中多次读取同一个对象属性,最佳做法是将属性值保存到存到局部变量中,因为局部变量的读取速度要更快。局部变量能用来代替属性以避免多次查找带来的性能开销,特别是在处理嵌套对象成员时。

// 一段雅虎的代码function toggle(element) {    if (YAHOO.util.Dom.hasClass(element, "selected")) {        YAHOO.util.Dom.removeClass(element, "selected");        return false;    } else {        YAHOO.util.Dom.addClass(element, "selected");        return true;    }}

这段代码中重复读取 YAHOO.util.Dom 3 次来读取 3 个不同的方法。我们可以使用一个局部变量将 YAHOO.util.Dom 保存起来,然后访问这个局部变量:

// 优化 将 3 次读取变成 1 次function toggle(element) {    var Dom = YAHOO.util.Dom;    if (Dom.hasClass(element, "selected")) {        Dom.removeClass(element, "selected");        return false;    } else {        Dom.addClass(element, "selected");        return true;    }}

将 3 次读取变成 1 次,优化了查找。

参考博客
[1] 深入理解javascript原型和闭包(完结)

附: 欢迎大家关注我的新浪微博 - 一点编程,了解最新动态 。

0 0
原创粉丝点击