原型链
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 生成原型对象。
在 JavaScript 中,继承是依靠一套叫做原型链(prototype chain)的机制实现的。属性继承的本质就是一个对象可以访问到它的原型链上任何一个原型对象的属性。例如上例的foo 对象,它拥有 foo. proto 和 foo. proto.proto 所有属性的浅拷贝(只复制基本数据类型,不复制对象)。所以可以直接访问foo.constructor(来自foo.proto,即Foo.prototype), foo.toString(来自foo. proto.proto,即Object.prototype)。