Page 169 - Node.js开发指南
P. 169
162 附录 A JavaScript 的高级特性
};
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.func1 == foo2.func1); // 输出 false
console.log(foo1.func2 == foo2.func2); // 输出 true
尽管如此,并不是说在构造函数内创建属性不好,而是两者各有适合的范围。那么我们
什么时候使用原型,什么时候使用构造函数内定义来创建属性呢?
除非必须用构造函数闭包,否则尽量用原型定义成员函数,因为这样可以减少开销。
尽量在构造函数内定义一般成员,尤其是对象或数组,因为用原型定义的成员是多个
实例共享的。
接下来,我们介绍一下JavaScript中的原型链机制。
原型链
JavaScript 中有两个特殊的对象: Object 与 Function,它们都是构造函数,用于生
成对象。Object.prototype 是所有对象的祖先,Function.prototype 是所有函数的原
型,包括构造函数。我把 JavaScript 中的对象分为三类,一类是用户创建的对象,一类是构
造函数对象,一类是原型对象。用户创建的对象,即一般意义上用 new 语句显式构造的对
象。构造函数对象指的是普通的构造函数,即通过 new 调用生成普通对象的函数。原型对象
特指构造函数 prototype 属性指向的对象。这三类对象中每一类都有一个 __proto__ 属
性,它指向该对象的原型,从任何对象沿着它开始遍历都可以追溯到 Object.prototype。
构造函数对象有 prototype 属性,指向一个原型对象,通过该构造函数创建对象时,被创
建对象的 __proto__ 属性将会指向构造函数的 prototype 属性。原型对象有 constructor
属性,指向它对应的构造函数。让我们通过下面这个例子来理解原型:
function Foo() {
}
Object.prototype.name = 'My Object';
Foo.prototype.name = 'Bar';
var obj = new Object();
var foo = new Foo();
console.log(obj.name); // 输出 My Object
console.log(foo.name); // 输出 Bar
console.log(foo.__proto__.name); // 输出 Bar
console.log(foo.__proto__.__proto__.name); // 输出 My Object
console.log(foo. __proto__.constructor.prototype.name); // 输出 Bar
我们定义了一个叫做 Foo ()的构造函数,生成了对象 foo。同时我们还分别给 Object
和 Foo 生成原型对象。