深入理解原型与原型链

583 阅读4分钟

原型与原型链

前言

原型与原型链,作为JavaScript中很关键的知识点之一,它的重要性是可想而知的,如果原型与原型链没有搞明白,会很影响你接下来的很多学习,例如js继承机制、TypeScript、vue框架等,所以原型与原型链是很重要的基础,也是每一名前端工程师必须研究透的

构造函数

讲到原型,就一定要先对构造函数有一定的基础

构造函数中有静态成员、实例成员、原型属性(一般是称为方法)

静态成员:在构造函数本身创建的属性,只能通过构造函数访问。

构造函数-静态成员.png 实例成员:在构造函数本身,通过this添加的成员,只能通过实例化对象访问。

构造函数-实例成员.png 原型属性:在构造函数的原型对象上创建的属性(方法)。

构造函数-原型属性.png

可能这么看不够直观,看图

构造函数.png 首先我们要知道,全局变量、局部变量、函数名都是储存在栈中的,而对象实体是储存在堆中的。

  1. 栈中的Person构造函数通过地址值0x123找到了堆中的Person构造函数对象,堆中的Person构造函数存放着实例成员(this.name,this.age,this.sayName)、静态成员(Person.uname)以及prototype(后面详细说)等属性

  2. prototype通过储存的地址值找到Person原型对象,这里存储着原型属性(sing函数)以及constructor等属性。

  3. 我们通过new实例化了构造函数Person,在内存堆中创建了person1实例对象,栈中person1通过地址值0x345找到堆中的person1实例对象,在new构造函数Person的时候发生这么一件事,就是构造函数内部的this被赋值为person1这个实例对象,同时构造函数中的实例成员全被添加到实例对象中,所以现在实例化对象中存有实例成员(this.name,this.age,this.sayName)以及__proto__(后面详细说)等属性。

new 构造函数后发生了什么

这块可以先放一放,不影响理解原型与原型链,但是理解了会有一种通透的感觉

  1. 创建一个新对象(实例对象)
    const person1 = new Object()
  1. 将this指向实例对象,并将构造函数中用this定义的属性复制到实例上(用call和apply都行)
    Person.apply(person1, [....])
  1. 将实例对象中的__proto__属性指向Person的原型(原来指向的是Object的原型对象)
    person1.__proto__ = Person.prototype

原型

个人习惯:prototype称为显式原型属性、__proto__([[prototype]])称为隐式原型属性。
prototype:

我们每创建一个函数,js引擎就会自动为了函数创建一个prototype属性,这个属性通过储存的地址值指向函数的原型对象(也是Object的实例对象),而原型对象会自动获得一个constructor属性,这个属性指回与之关联的构造函数。

上面我们说函数的原型对象,也是Object的实例对象,在我们调用函数时(Fun()),其实相当于执行了Fun.constructor = new Object()这段代码

__proto__:

注:现在谷歌浏览器显示这个属性为[[prototype]],每次实例化构造函数,创建一个实例对象,其内部会有一个__proto__属性,指向构造函数的原型对象,在内部的操作的是:实例化构造函数——>将构造函数中prototype储存的地址值拷贝一份赋值给实例对象__proto__属性——>结果就是__proto__属性指向原型对象

我们可以通过代码验证prototype、__proto__、constructor

构造函数-原型.png

原型链

你有没有疑惑过我明明没有定义过toString()方法,但是我在哪都可以使用这个方法?答案很简单,这得益于原型链。

理解原型与原型链最好的方法是就是将原型可视化。

以上面代码为例 原型1.png

  1. 我们可以看到Person构造函数中有显式原型prototype属性指向他的原型,原型中又有一个constructor属性指回Person构造函数,
  2. 而实例对象中有隐式原型属性__proto__也指向Person原型对象,此时我们注意Person原型,因为他也是Object的实例对象,所有它也有一个隐式原型__proto__属性指向Object原型,
  3. 我们再看Objet原型,他的隐式原型属性__proto__指向null,意味着空。所以Object原型就是整个原型链的终点。

对于这段代码来说,他的原型链就是:person1实例对象——>Person原型对象(Object的实例对象)——>Object原型对象。可以发现原型链是沿着隐式原型属性__proto__走的,所以也称为隐式原型链。

把前面都弄懂,最后尝试理解以下这个图

如果你能理解、说出这里每一条线产生的原因,并且脱离了这张图,看到图中的一个词立马能在脑中浮现出与它相关的指向,那么恭喜你,你在后面理解继承,以及学习TS类继承的时候,几乎无压力,全程绿灯,这点我深有感触。

原型链.webp

最后

我是小k,一名2023届毕业生,感谢你的观看