一、原型检测
javascript中提供Object.getPrototypeOf()
方法来获得对象的直接原型。
function Person() { this.name = 'sillywa'}var person1 = new Person()Object.getPrototypeOf(person1) // {constructor: ƒ Person()}Object.getPrototypeOf(person1.__proto__) // Object.prototypevar person = { name: 'sillywa'}var person2 = Object.create(person)Object.getPrototypeOf(person2) // {name: "sillywa"}复制代码
javascript有以下几种方法检测一个对象的原型:
isPrototypeOf()
:检测一个对象是否是另一个对象的原型obj.constructor.prototype
:检测非Object.create()
创建的对象的原型
var obj1 = { name: 'sillywa'}var obj2 = Object.create(obj1)// isPrototypeOf()方法Object.prototype.isPrototypeOf(obj1) // trueobj1.isPrototypeOf(obj2) // trueObject.prototype.isPrototypeOf(obj2) // true// obj.constructor.prototypeobj1.constructor.prototype === Object.prototype // true// obj1是obj2的原型,以下等式应为trueobj2.constructor.prototype === obj1 // false// 而实际上obj2.constructor.prototype === Object.prototype // true复制代码
以上代码中obj1
是obj2
的原型,obj2.constructor.prototype === obj1
应为true
但是实际上却是false
,因为obj2
的__proto__
里面并没有一个constructor
属性,obj2.constructor
实际上是obj1
的__proto__
里面的constructor
,所以obj2.constructor.prototype === Object.prototype
。
一、constructor
、__proto__
与prototype
之间的关系
在javascript中我们每创建一个对象,该对象都会获得一个__proto__
属性(该属性是个对象),该属性指向创建该对象的构造函数的原型
即prototype
,同时__proto__
对象有一个constructor
属性指向该构造函数。这里我们需要注意的是只有函数才有prototype
,每个对象(函数也是对象)都有__proto__
,Object
本身是个构造函数。举例来说:
var obj = new Object()// 也可以使用对象字面量创建,但使用Object.create()情况会不一样// Object本身是个构造函数Object instanceof Function // trueobj.__proto__ === Object.prototype // trueobj.__proto__.constructor === Object // true// 我们一般习惯这样写obj.constructor === Object // true复制代码
当我们访问obj.constructor
的时候,obj
本身是没有constructor
属性的,但属性访问会沿着__proto__
向上查找,即在obj.__proto__
里面寻找constructor
属性,如果找到了就返回值,如果未找到则继续向上查找直到obj.__proto__.__proto__...(__proto__) === null
为止,没有找到则返回undefined。这样由__proto__
构成的一条查找属性的线称为‘原型链’。
二、进一步探讨
我们知道JS是单继承的,Object.prototype
是原型链的顶端,所有对象从它继承了包括toString
等等方法和属性。
前面我们说到Object
本身是构造函数,那么它继承了Function.prototype
;Function
也是对象,继承了Object.prototype
。这里就有一个鸡和蛋的问题:
Object instanceof Function // trueFunction instanceof Object // true复制代码
以下是ES规范的解释:
Function
本身就是函数,Function.__proto__
是标准的内置对象Function.prototype
。Function.prototype.__proto__
是标准的内置对象Object.prototype
。
function Person(name) { this.name = name}var person1 = new Person('sillywa')复制代码
总的来说:先有Object.prototype
(原型链顶端),Function.prototype
继承Object.prototype
而产生,最后,Function
和Object
和其它构造函数继承Function.prototype
而产生。
三、Object.create()
我们知道通过Object.create()
创建的对象实际上等于将该对象的__proto__
指向Object.create()
里面的参数对象,那么当涉及到原型时它是怎么工作的呢?
var a = { name: 'sillywa'}var b = Object.create(a)b.__proto__ === Object.prototype // falseb.__proto__ === a // trueb.__proto__.constructor === Object // trueb.__proto__.hasOwnProperty('constructor') // false复制代码
下面我们来具体看一看当var b = Object.create(a)
到底发生了什么,以下实在浏览器中的结果:
var b = Object.create(a)
实际上是把 b
的 __proto__
指向了 a
。当访问 b.constructor
时,实际上访问的是 b.__proto__.__proto__.constructor
。 四、实例与总结
function Person(name) { this.name = name}var person1 = new Person('sillywa')person1.__proto__ === Person.prototypeperson1.__proto__.__proto__ === Person.prototype.__proto__person1.__proto__.__proto__ === Object.prototypePerson.prototype.__proto__ === Object.prototype person1.__proto__.__proto__.__proto__ === nullPerson.__proto__ === Function.prototype复制代码
以上均返回true
,前五个等式和第一部分内容相关,最后一个等式为第二部分内容,需要注意的是IE浏览器里面并没有实现__proto__
,为了便于理解我们可以这样解释,但是最好不要在实际中使用