理论篇:深入解析js中prototype、__proto__、constructor

前言

搞懂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。
相关推荐
白墨阳几秒前
vue3:瀑布流
前端·javascript·vue.js
霍先生的虚拟宇宙网络30 分钟前
webp 网页如何录屏?
开发语言·前端·javascript
温吞-ing32 分钟前
第十章JavaScript的应用
开发语言·javascript·ecmascript
彪82533 分钟前
第十章 JavaScript的应用 习题
javascript·css·ecmascript·html5
jessezappy1 小时前
jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
前端·word·jquery·filesaver·word-export
旧林8431 小时前
第八章 利用CSS制作导航菜单
前端·css
yngsqq1 小时前
c#使用高版本8.0步骤
java·前端·c#
Myli_ing2 小时前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风2 小时前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave2 小时前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习