理论篇:深入解析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。
相关推荐
千穹凌帝几秒前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
dot.Net安全矩阵11 分钟前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
叫我:松哥15 分钟前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
Hellc00722 分钟前
MacOS升级ruby版本
前端·macos·ruby
前端西瓜哥31 分钟前
贝塞尔曲线算法:求贝塞尔曲线和直线的交点
前端·算法
又写了一天BUG32 分钟前
npm install安装缓慢及npm更换源
前端·npm·node.js
cc蒲公英1 小时前
Vue2+vue-office/excel 实现在线加载Excel文件预览
前端·vue.js·excel
Java开发追求者1 小时前
在CSS中换行word-break: break-word和 word-break: break-all区别
前端·css·word
好名字08211 小时前
monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)
前端·javascript
pink大呲花1 小时前
css鼠标常用样式
前端·css·计算机外设