构造函数、this指向和原型链机制

今天在刷力扣 [146. LRU 缓存](https://leetcode.cn/problems/lru-cache/) 的时候,遇到了原型链的写法,想想这个写法我正式开发中从来都没有用过,到底是个什么玩意?遂将各个节点和变量都定义在外面,但是代码居然报错啦!

问了哈吉米大人后才知道代码逻辑没问题,但由于力扣每次测试的时候全局定义的变量是不会重置的,导致数据残留,因此看到了原型链写法,了解之后才知道它就是通常说的 class 写法,只不过 JavaScript 语言早期的缺陷没有考虑到,只能用原型链代替;

但还好,ES6 还是加上了 classclass 本质上只是"语法糖",它的底层运行机制依然是我们刚刚讲过的"原型链"。


在普通的面向对象语言(比如 Java/C++)里,有明确的 class(类)概念。但在早期的 JavaScript(ES6 之前)里,是没有真正的 class 的,大家只能用函数来"客串"类。

一、 new 操作符的"四步魔法"

在构造函数中,this 永远指向那个正在被 new 创造出来的新实例对象本身。

1、 凭空创建: 在内存中创建一个全新的、空的 JavaScript 对象(例如 let obj = {};)。

2、 基因绑定(链接原型): 将这个新对象的隐藏属性 __proto__ 指向构造函数的 prototype(共享包)。

3、 灵魂附体(绑定 this): 将构造函数内部的 this 强行指向这个刚刚创建的新对象,并执行函数体内的代码(为新对象添加各种属性)。

4、 自动交货: 函数执行完毕后,自动返回这个填满属性的新对象(除非你的函数手动返回了另一个对象)。

二、 原型 (prototype) 与 原型链

为什么需要原型?

为了节省内存。如果把所有方法(如 getput)都写在构造函数内部,每次 new 一个新实例,内存中就会复制一份全新的函数代码。

核心概念拆解

prototype(显式原型 / 共享技能包): 每个函数出生时自带的属性。我们把所有实例共用的方法挂载在这里(如 LRUCache.prototype.get = ...)。

__proto__(隐式原型 / 寻址网线): 每个实例对象自带的隐藏属性。它指向创造它的那个构造函数的 prototype

原型链的工作机制

当调用 cache.get() 时:

Step 1:JS 引擎先在 cache 这个对象自己的肚子里找 get 方法。

Step 2:找不到,就顺着 cache.__proto__ 爬到 LRUCache.prototype(共享包)里去找。

Step 3:如果共享包里还没有,继续顺着网线往上爬,直到找到顶级对象 Object.prototype。如果还是没有,就返回 undefined 或报错。这就是原型链。

原型链关系示意图

下面通过 Mermaid 流程图直观展示 cache 实例、LRUCache.prototypeObject.prototype 之间的原型链关系:
顶级原型 (Object.prototype)
构造函数原型 (LRUCache.prototype)
实例对象 (cache)
proto 指向
proto 指向
proto 指向
cache 实例

自身属性: capacity, cache, head, tail...
LRUCache.prototype

共享方法: get(), put(), ...
Object.prototype

基础方法: toString(), hasOwnProperty(), ...
null

图例说明:

  • cache 实例: 通过 new LRUCache(capacity) 创建的具体对象,包含实例特有的属性
  • LRUCache.prototype: 构造函数的原型对象,存储所有实例共享的方法
  • Object.prototype: JavaScript 中所有对象的最终原型,提供基础方法
  • __proto__ 链接: 实例通过 __proto__ 属性指向其构造函数的原型,形成原型链

当调用 cache.get() 时,JavaScript 引擎会沿着这条链向上查找:

  1. 先在 cache 自身查找 get 方法
  2. 找不到 → 通过 cache.__proto__ 找到 LRUCache.prototype
  3. LRUCache.prototype 中找到并执行 get 方法
  4. 如果还找不到,继续向上到 Object.prototype,最终到 null

三、 this 的指向法则

黄金定律:谁调用了它,this 就指向谁!(看点 . 的左边)

  • 默认调用(独立函数):func() 没有点调用,this 默认指向全局对象(浏览器环境是 window,严格模式下是 undefined)。
  • 隐式绑定(方法调用):obj.func() 点左边是 objfunc 内部的 this 瞬间指向 obj
  • new 绑定(构造调用):new Func() this 指向全新被构造出来的实例对象。
相关推荐
WHS-_-20222 小时前
Millimeter Wave ISAC-SLAM: Framework and RFSoC Prototype
人工智能·算法·原型模式
吃好睡好便好2 小时前
在Matlab中绘制杆状图
开发语言·学习·算法·matlab·信息可视化
带带弟弟学爬虫__2 小时前
dyAPP数据采集-个人主页、发布、搜索、评论
服务器·python·算法·flutter·java-ee·django
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章75-线-线角度
图像处理·人工智能·opencv·算法·计算机视觉
大熊背2 小时前
Binning模式下和Normal模式下加权平均亮度差异分析以及优化
人工智能·算法·自动曝光
思茂信息2 小时前
CST案例:可调谐全硅手性超表面在太赫兹频段
网络·人工智能·算法·重构·cst·电磁仿真
Maimai108082 小时前
React 多步骤表单工程化落地:从 Zod Schema、React Hook Form 到 Zustand 持久化
前端·javascript·react.js·前端框架·状态模式
Maimai108082 小时前
React Query + Zustand 正确结合方式:不要把接口数据复制进 Store
前端·javascript·react.js·前端框架·web3·状态模式
yzin2 小时前
cjs 和 esm 的差异总结&最佳实践
前端·javascript