前言: ES6 已经广泛运用于 nodejs 中,类的写法也由 Function 升级到了 Class。然而,Class 只是过往 ES5 环境中 Function 的语法糖,所以以往 function 写法构建类时候的很多操作和知识点,同样会延续到 es6 的类写法 class 中。故而,不妨重新回顾一下 ES5 中原型链的一些特性。
准备知识
- JavaScript 中,万物皆为对象,__proto__ 存在于每一个对象中
- 方法 ( Function ) 是对象,方法的原型 ( Function.prototype ) 也同样是对象,对象具有属性 __proto__ ( 隐式原型 ),一个对象的隐式原型指向构造该对象的构造函数的原型,这保证了实例能够访问在构造函数原型中定义的属性和方法
- Function 比较特殊,它除了和其他对象一样含有上述 __proto__ 以外,还具有期特有的原型属性 prototype ( 显式原型 ),该对象是一个指针,指向一个对象(原型对象),这个对象包含了所有实例共享的属性和方法。需要注意的是,在原型对象中,包含一个 constructor 的属性,该属性指回原构造函数
__proto__ 和 prototype 关系图
new 方式产生的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| function Foo(){}
var f1 = new Foo(); var o1 = new Object();
f1.__proto__ === Foo.prototype
Foo.prototype.__proto__ === Object.prototype
Foo.prototype.constructor === Foo
Foo.__proto__ === Function.prototype
Object.prototype.__proto__ === null
Object.__proto__ === Function.prototype
Function.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
|
对象字面量方式产生的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var obj = {};
obj.__proto__ === Object.prototype
obj.__proto__.__proto__ === null
obj.__proto__.constructor === Object
obj.__proto__.constructor.__proto__ === Function.prototype
obj.__proto__.constructor.__proto__.__proto__ === Object.prototype
obj.__proto__.constructor.__proto__.__proto__.__proto__ === null
obj.__proto__.constructor.__proto__.__proto__.constructor.__proto__ === Function.prototype
|
Object.create 方式产生的对象
我们首先看下 create 的内部实现(近似)
1 2 3 4 5 6
| Object.create = function(p) { function f(){} f.prototype = p; return new f(); }
|
create 操作,实际是构建了一个新的函数,并且把该函数的 prototype 指向原始对象 p,再用 new 操作生成一个新对象,故而执行结果就很明了了,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var p1 = {}; var p2 = Object.create(p1);
// p2.__proto__ 指向生成它的构造函数的原型属性 // 由于构造函数的 prototype 被强制指定为了 p ( 这里的 p1 ) // 故而 p2.__proto__ 指向 p1 p2.__proto__ === p1
// p1.constructor 为 Object,故而 p1.__proto__ 指向 Object.prototype // 即 p1.__proto__ 指向 p1.constructor.prototype p1.__proto__ === p1.constructor.prototype
// 由于 create 操作会丢失构造器,故而此处不等,如下图所示 p2.__proto__ !== p2.constructor.prototype
|
p2 由 create 而来,丢失了构造器,而 p1 则没有