首先,需要知道以下事实:
- Javascript的继承是基于原型链模式的。
- Javascript的原型是一个对象。
- Javascript的继承本质是一(或多)个对象引用了另一个对象的属性和方法。
直接结论:
__proto__ 是对象的一个内部隐藏属性,它的值是该对象的原型。
prototype 是函数对象的一个属性,它的值是一个对象(默认为 {} ),当该函数用作构造函数时,新创建对象的原型(__proto__)将指向该属性值。
好,show you the code:
> var A = function(x){this.name = x;}; //定义函数 A
> var a = new A('ima'); // 通过函数A创建对象a
> a
{ name: 'ima' }
> A.prototype //因为A.prototype默认是 {}
{}
> a.__proto__ //所以对象a的原型(__proto__)就是 {}
{}
> A.prototype === a.__proto__ //它们都是指向同一个 {}
true
> {} === {} //js中不同的空对象引用不一样,请对比上者感受一下
false
再展示另一个例子:
> var D = function(y){this.desc = y;}; //定义函数D
> D.prototype = a; //将D的prototype指向对象a
{ name: 'ima' }
> var d = new D('imd') //通过函数D创建对象d
> d
{ desc: 'imd' }
> d.__proto__ //对象d的原型就是对象a
{ name: 'ima' }
> d.__proto__ === a
true
> d.name //d"继承"了对象a的属性,实质是引用
'ima'
> a.name = 'iama!' //更改a.name, d.name也发生了改变
> d.name //具体可以查看Javascript原型链原理
'iama!'
/* 需要注意的是:非函数对象是没有prototype属性的:*/
> a.prototype
undefined
> d.prototype
undefined
/* 而函数是有__proto__的,因为函数也是对象:*/
> A.__proto__
[Function: Empty] //函数的默认原型是空函数,正如对象的默认原型是空对象
> A.__proto__.toString()
'function Empty() {}'
再次总结:
- __protot__指向对象的原型。
- prototype是函数的属性,作为使用new创建的函数实例的原型。
建议阅读阮一峰的Javascript继承机制的设计思想,简单通俗地了解为什么Javascript采用prototype这种方式实现继承。
题外话:(关于constructor)
/* 对象a的构造函数是函数A */
> a.constructor.toString()
'function (x){this.name = x;}'
> a.constructor === A
true
/* 因为A是一个函数对象,所以A的构造函数就是function的构造函数Function */
> A.constructor
[Function: Function]
> A.constructor.toString()
'function Function() { [native code] }'
> A.constructor === Function.constructor
true
/* 函数A的原型(__protot__)就是它的构造函数(Function)的prototype */
> A.constructor === Function
true
> Function.prototype
[Function: Empty]
> A.__proto__ === Function.prototype
true
/* 但是 !!! */
/* 继承了对象a的d,它的构造函数不是D,而是A */
> d.constructor.toString()
'function (x){this.name = x;}'
> d.constructor === a.constructor
true
> d.constructor === A
true
以上代码在Node.js v0.10.30环境下测试。