关于对象-函数-原型的关系

134 阅读4分钟

关于对象-函数-原型的关系

​非常感谢王红元老师,在学习了他的JS课程中关于对象,函数和原型关系的一节课程后,令我茅塞顿开,困扰我多年的难题如同一座巨大的雪山在丝丝春雨的浸润下逐渐消融。第一次如此冲动的想去记录下来并分享给大家,希望可以帮助到大家。

​在理解对象-函数-原型的关系之前,我先向大家介绍下对象的原型函数的原型,这对于后面的理解十分关键

对象的原型

  • 在JS中每一个对象都会有一个内置的属性[[prototype]],这个属性可以指向另外一个对象,这个对象就是对象原型,也别称之为隐式原型
  • 但是在早期的ECMA中没有关于如何去查看这个对象原型的方法
  • 所以部分浏览器和node就提供了一个属性去查看对象原型,就是大家熟悉的__proto__
    • image-20211223195925242.png
  • ES5以后官方推出了Object.getPrototypeOf()去查看prototype(对象原型)
    • image-20211223200511455.png
  • __proto__这个属性在我们日常开发中经常会作为测试工具,但不建议出现在你最终的代码里
  • 当我们从一个对象中去获取某个属性时,会触发get操作,
    • 如果在当前对象中找到该属性,就直接使用
    • 如果没有找到,就会沿着这个对象的原型链去查找,也就是找到对象原型
    • image-20211223200647145.png
    • 如果一直没有沿着原型链寻找,我们可以看到结果是null
    • image-20211223204047068.png
    • 因为obj是通过new Object()创建出来的,所以obj.__proto__ = Object.prototype,所以Object.prototype就是顶层原型

函数的原型

  • 在JS中万物皆对象,当然函数本身也算对象,所以函数也会有对象原型[[prototype]]

  • image-20211223200838663.png

  • 但是函数作为函数,还会多出来一个属性,就是prototype,这个prototype可不同于上面提到的[[prototype]],这个prototype是作为函数的属性存在的,也被称之为显示原型

  • image-20211223200908641.png

  • 当你使用构造函数时,肯定离不开new,new 操作符有一个作用:创建出来的对象的隐式原型被赋值为该构造函数的显示原型,所以该将对象隐式原型会指向函数显示原型

  • image-20211223202218146.png

  • 函数原型上有一个属constructor,constructor中有很多配置,有机会我再写一篇,先不用理解,只需知道该属性指向构造函数本身

  • image-20211223203441233.png

  • 因为foo函数的原型对象也是对象,是被new Object()创建出来的,所以foo.__proto.__=Object.prototype

    image-20211223204838298.png

理解原型链图

在这里插入图片描述

image-20211223205441146.png

// 通过代码解释
var f1 = new Foo();
f1.__proto__===Foo.prototype // f1是通过Foo函数创建出来的对象,所以会将Foo的显式原型(prototype)赋值给f1的隐式原型(__proto__)
Foo.prototype.constructor === Foo // 函数原型对象中的constructor指向函数构造器本身

image-20211223205859561.png

function Foo(){};
Foo.prototype.__proto__ === Object.prototype // 因为Foo.prototype(函数原型对象)是被new Object创建出来的,所以会将Object的显式原型(prototype)赋值给Foo.prototype的隐式原型(__proto__)
Foo.__proto__ === Function.prototype // 因为Foo(函数)是被new Function创建出来的,所以会将Function的显式原型(prototype)赋值给Foo的隐式原型(__proto__)
Function.prototype.__proto__ === Object.prototype // 因为Foo.prototype(函数原型对象)是被new Object创建出来的,所以会将Object的显式原型(prototype)赋值给Foo.prototype的隐式原型(__proto__)
Object.prototype.__proto__ === null // 这就是我们前面提到的顶层原型

image-20211223211158300.png

var o1 = new Object();
o1.__proto__ === Object.prototype; // 因为o1(对象)是被new Object创建出来的,所以会将Object的显式原型(prototype)赋值给o1的隐式原型(__proto__)

image-20211223211842722.png

Object.__proto__ === Function.prototype // 因为Object(本身也是函数)是被new Function创建出来的,所以会将Function的显式原型(prototype)赋值给函数Object的隐式原型(__proto__)

image-20211223212120524.png

Object.prototype.constructor === Object // 函数原型对象中的constructor指向函数构造器本身
Function.prototype.constructor === Function // 函数原型对象中的constructor指向函数构造器本身
Function.__proto__ === Function.prototype // 因为Function(本身也是函数)是被new Function创建出来的,所以会将Function的显式原型(prototype)赋值给Function的隐式原型(__proto__),这也是唯一最特殊的一条

第一次写,改了写,写了改,希望大家多多指正,为了美好的明天,继续加油!