《JS原型》
@(JavaScript原型)
JavaScript中最晦涩难懂的恐怕就是原型了。故以此笔记本来记录原型的学习过程,日后忘了可来温习。
一切皆为对象
null
——Object
&Function
——prototype
&constructor
原型指针 __proto__
在JavaScript中,每个对象都拥有一个原型对象,而指向该原型对象的内部指针则是
__proto__
,通过它可以从中继承原型对象的属性。从对象的__proto__
可以访问到它所继承的原型对象。
var a = new Array();
a.__proto__ === Array.prototype //true
a.__proto__.__proto__ === Object.prototype //true
a.__proto__.__proto__.__proto__ === null //true
如图,JavaScript中的对象,追根溯源都是来自一个
null
对象。
除了使用.__proto__
方式访问对象的原型,还可以通过Object.getPrototypeOf
方法来获取对象的原型,以及通过Object.setPrototypeOf
方法来重写对象的原型。
原型对象prototype
函数既是函数又是对象,函数的原型指向
Function.prototype
,函数实例除了有__proto__
属性之外,还有prototype
属性。通过该函数构造的新的实例对象,其原型指针__pro__
会指向该函数的prototype
属性。而函数的prototype
属性,本身是一个由Object
构造的实例对象。prototype
属性很特殊,它还有一个隐式的constructor
,指向了构造函数本身。
var Foo = function() {};
Foo.__proto__ === Function.prototype //true
var a = new Foo();
a.__proto__ === Foo.prototype //true
Foo.prototype.__proto__ === Object.prototype //true
Foo.prototype.constructor === Foo //true
a.constructor === Foo //true
a.constructor === Foo.prototype.constructor //true
a.constructor
属性并不属于a
而是读取的a.__proto__.constructor
,所以上图用虚线表示a.constructor
,方便理解。
即(a.hasOwnProperty("constructor")===false
)
原型链:
原型链作为实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
每个构造函数都有一个原型对象(prototype
),原型对象都包含一个指向构造函数的指针(constructor
),而实例都包含一个指向原型对象的内部指针。
原型链的作用在于,当读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。以此类推,如果直到最顶层的Object.prototype
还是找不到,则返回undefined
。
亲子鉴定
instanceof
运算符返回一个布尔值,表示一个对象是否由某个构造函数创建。Object.isPrototypeOf()
只要某个对象处于原型链上,isPrototypeOf
都 返回true
var Bar = function() {};
var b = new Bar();
b instanceof Bar //true
Bar.prototype.isPrototypeOf(b) //true
Object.prototype.isPrototypeOf(Bar) //true
注意:实例
b
的原型是Bar.prototype
而不是Bar
。
一个有趣的地方:
Function.prototype.__proto__ === Object.prototype
Object.prototype.constructor.__proto__ === Function.prototype
即说明Function.prototype
是一个Object
实例,而没有Function
,Object
也不能创建实例。
如下图:
其中,Op
代表Object.prototype
,Fp
代表Function.prototype
。
以上,参考@Jerrc
---恢复内容结束---
@(JavaScript原型)