在类继承的语言中,好比 Java ,使用了类来描述实例对象的行为。JavaScript 中没有类,因此也没有使用类继承。采用的是原型继承的方式。javascript
原型继承使用对象来描述实例对象的行为,这个描述行为的对象就是原型对象(prototype)。java
prototype 是全部函数都具备的属性。当一个函数被做为构造函数生成一个实例对象时,prototype 就是这个实例对象的原型对象。浏览器
constructor 表示生成该实例对象的构造函数。 可是实例对象是不存在 constructor 属性的,这个属性被保存在了原型对象中。缓存
来看实例:bash
function Foo(){}
var foo1 = new Foo()
console.log(foo1)
console.log(Foo.prototype)
console.log(foo1.constructor === Foo.prototype.constructor)
复制代码
结果以下: 函数
咱们能够看到 foo1 对象中是不包含 constructor 属性的,而 Foo.prototype 中存在 constructor 属性。可是 foo1 的 constructor 值和 Foo.prototype 的 constructor 值倒是相等的。说明 foo1 的 constructor 属性实际上是从 Foo.prototype 继承过来的。这种将属性不保存在自身,却能经过自身访问获得的设计被称为行为委托。post
在上图中,咱们看到在 foo1 对象和 Foo.prototype 对象中都有一个属性 __proto__ 。ui
那么 __proto__ 是什么呢? 在继承中,咱们须要一种向上查找的能力去维持继承关系。对于 JavaScript 来讲就是实例对象查找实例原型,子原型对象查找父原型对象,父原型对象继续向上查找直到根原型对象,也就是 Object.prototype,Object.prototype向上查找会获得一个 null 值,指示查找结束。整个查询路径构成了原型链。this
在浏览器的实现中,使用了 __proto__ 属性来缓存原型对象,全部的对象都拥有这个属性。这样对象经过查询 __proto__ 属性便能实现向上查找。spa
来看实例:
function Foo(){}
var foo1 = new Foo()
console.log(foo1.__proto__ === Foo.prototype) // true
console.log(Foo.prototype.__proto__ === Object.prototype) // true
复制代码
实例对象 foo1 的 __proto__ 属性缓存着原型对象 Foo.prototype 。子原型对象 Foo.prototype 的 __proto__ 属性缓存着父原型对象 Object.prototype。
从 constructor、prototype、__proto__ 这三个角度去思考,咱们便能很快的画出整个图示。
先来思考 constructor ,原型对象的构造函数表示生成实例对象的构造函数,由此得出下图:
再来思考 prototype,构造函数的 prototype 就是原型对象。补充得出下图:
最后来思考 __proto__,实例对象的 __proto__属性缓存着原型对象,原型对象的 __proto__缓存着父原型对象。 实例对象是由构造函数使用 new 操做符生成的。补充得出下图:
instanceof 运算符用来检测一个对象的原型链中是否存在指定构造函数的原型对象。
用法以下:
object instanceof constructor
复制代码
来看实例:
function Foo(){}
var foo1 = new Foo()
console.log(foo1 instanceof Foo) // true
console.log(foo1 instanceof Object) // true
复制代码
经过图示,咱们能够清楚地看到 Foo.prototype 和 Object.prototype 都位于原型链中。
ECMAScript 5 提供的 Object.getPrototypeOf 能够用来查看实例对象的原型。
function Foo(){}
var foo1 = new Foo()
console.log(Object.getPrototypeOf(foo1 ) === Foo.prototype) // true
console.log(Object.getPrototypeOf(foo1 ) === Object.prototype) //false
复制代码
关于内建对象:
关于内建函数:
理解上面的两个要点,就能理解下面的例子了
Function.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
复制代码
Function 是内建函数是由 Function() 建立而来,因此它的 __proto__ 属性中缓存着 Function.prototype。同理可得Object.__proto__ === Function.prototype
。
Function.__proto__.__proto__ === Object.prototype // true
Object.__proto__.__proto__ === Object.prototype // true
Object.__proto__.__proto__.__proto__ === null // true
复制代码
Function.__proto__是一个内建原型对象,是由 Object() 建立而来的。因此它的 __proto__属性中缓存着 Object.prototype。同理可得 Object.__proto__.__proto__ === Object.prototype
。 既然 Object.__proto__.__proto__ === Object.prototype
,而 Object.prototype.__proto__ === null ,因此Object.__proto__.__proto__.__proto__ === null