前言
搞懂JS中的 prototype
、__proto__
、constructor
之间的关系是每一位前端工程师的必修课。
结合上一篇 javascript原型链继承的设计思想 继续梳理构造函数、原型和实例三者之间的关系:每个构造函数都有一个原型对象 ,原型对象都包含一个指向构造函数的指针,实例都包含一个原型对象的内部指针。
__ proto __
实例对象可以访问构造函数原型对象中的属性,它们是如何关联起来的?
一个对象的隐式原型指向构造该对象的构造函数的原型,这就保证了实例能够访问在构造函数原型中定义的属性和方法
作用 :当查找某个对象属性时,在当前对象内不存在这个属性,它可以通过__proto__去它的父对象中查找,找不到再通过父对象的__proto__对象往上找,直至原型链的终点 null
任何函数都可以看做是通过 Function()构造函数new操作实例化的结果
。如果把函数Foo/Object/Function也看作是实例化对象,那么他们的构造函数都是Function
js
Foo.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
注意:内部插槽 [[Prototype]]
可以通过 Object.getPrototypeOf()
和Object.setPrototypeOf()
函数来访问。这个等同于 JavaScript 的非标准但被许多 JavaScript 引擎实现的属性 __proto__
访问器。
prototype
作用:定义所有实例共享的属性或方法
任何函数都可以看成是Function()构造函数new操作的实例化对象
。那么,Function 也可以看成是调用其自身的new操作的实例化结果。如果Function作为实例对象,其构造函数是Function,其原型对象是Function.prototype,故:
js
Function.prototype.constructor === Function // true
Function.__proto__ === Function.prototype // true
如果Function.prototype作为实例对象的话,其原型对象是什么呢?所有的对象都可以看成是Object()构造函数new操作的实例化结果
。所以,Function.prototype的原型对象是Object.prototype,其原型函数是Object()
js
Function.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null // true
Function instanceof Object // true
Object instanceof Function // true
prototype是函数才会有的属性(注意:箭头函数没有原型对象
)
js
const fun = () => {};
console.log(fun.prototype); // undefined
constructor
constructor 是原型对象中的一个属性,这个属性包含了一个指针,指向该对象的构造函数,所有函数最终的构造函数都指向 Function
因实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,也指向原型对象对应的构造函数
js
function Parent() {}
function Child() {}
Child.prototype = new Parent();
const instance = new Child();
console.log(instance.constructor); // parent
任何一个prototype对象都有一个constructor属性
,指向它的构造函数,Child.prototype.constructor原本应该指向Child,但执行Child.prototype = new Parent()后它指向了Parent,而访问实例对象的constructor属性时,默认调用prototype对象的constructor属性,因此实例对象的constructor也是指向的Parent。
为防止继承链混乱,我们需要手动纠正:
js
Child.prototype.constructor = Child;
console.log(instance.constructor); // Child
Function.__ proto __ === Function.prototype
在JavaScript中,Function
本身是一个函数,也是一个对象,也是JavaScript中所有函数对象的构造函数。自然地拥有 __proto__
属性和 prototype
属性。它由自己创建,这是JavaScript设计的一部分。这个设计意味着 Function
作为一个对象,遵循同样的原型继承规则,只是它比较特殊,它的原型链顶端就是自己的 prototype
属性。
js
Function.constructor === Function // true
Object.constructor === Function // true
Object.__proto__.constructor === Function // true
总结
- prototype是函数独有的属性(箭头函数没有原型对象),因为函数也是一种对象,所以函数也拥有__proto__和constructor属性。
任何函数都可以看做是通过Function()构造函数new操作的实例化结果
所以函数可以作为实例对象,其构造函数是Function(),原型对象是Function.prototype。所有的对象都可以看成是Object()构造函数new操作的实例化结果
所以对象可以作为实例对象,其构造函数是Object(),原型对象是Object.prototype。