当前位置: 首页 > news >正文

Javascript:类中的成员变量及其this的理解

先看下经典代码,如下所示:

最标准原生 JS 类写法

// 定义一个类
class Demo {// 类中的普通成员变量name = "张三";// 类中的普通成员函数showInfo() {// 函数内部使用当前类的成员变量console.log(this.name);}
}// 实例化类
let obj = new Demo();// 调用方法
obj.showInfo();

ES5 老式写法(与上面等价的)

function Demo() {// 普通变量this.name = "李四";
}// 原型普通函数
Demo.prototype.show = function(){console.log(this.name);
};let obj = new Demo();
obj.show();

再列举一个例子进行说明:

class Person {// 实例自身的普通成员变量msg = "底层原理";// 普通成员方法print() {console.log(this.msg);}
}const p = new Person();
p.print();

1、this 核心本质

在类的普通成员函数中:this 永远指向当前被 new 出来的实例对象

2、内存结构图直白解释

  1. new Person() 执行时,会在堆内存开辟一块空间,这就是实例对象
  2. msg 这个变量,直接挂载在这个实例对象自身上。
  3. print 函数不在实例上,存在类的原型 (prototype) 上。
  4. 当你执行 p.print()
    • 调用者是 p 实例
    • 函数内部的 this 就自动绑定为调用者 p
    • 所以 this.msg 等价于 p.msg

致命易错点(必考)

class Person {msg = "底层原理";print() {console.log(this.msg);}
}const p = new Person();// 单独提取函数出来
const fn = p.print;
fn();

此时打印:undefined

原因

  • p.print() 调用:前面有对象,this 绑定 p
  • fn() 直接独立调用:前面无调用者,浏览器模式下 this 指向 window,window 上没有 msg

箭头函数完美解决(类里面写法)

class Person {msg = "底层原理";// 箭头函数写法print = () => {console.log(this.msg);}
}const p = new Person();
const fn = p.print;
fn(); // 正常打印

原理:

箭头函数本身没有自己的 this,它会继承定义时外层的 this,永远绑定当前实例,永不改变。
 

总结一句话

  1. 普通成员函数:this 看调用者
  2. 箭头成员函数:this 看定义位置,永久绑定实例

----------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------

继续看实例,从作用域链的角度进行分析,如下:

class Person {// 实例自身的普通成员变量msg = "底层原理";// 普通成员方法print() {console.log(msg);}
}const p = new Person();
p.print();

以上代码中的没有使用this,我们探讨一下JavaScript 类内部的作用域规则、变量查找机制,以及普通成员变量 / 方法的本质。

先直接说结论:
 
代码报错 msg is not defined,根本原因是:print 方法内部找不到变量 msg —— 类成员变量不是 “局部变量”,不会自动进入方法的作用域链。

1. 先拆解代码的执行与作用域结构

我们把代码翻译成底层实际运行的逻辑,你会瞬间明白:
class Person {// 这是【实例成员变量】// 等价于:constructor 里写 this.msg = "底层原理"msg = "底层原理";// 这是【原型方法】print() {// 关键:这里的代码执行时,作用域里根本没有 msgconsole.log(msg); }
}
 
类内部不是一个统一的作用域
  • msg = ...实例属性,挂载在 this(注意:这是实例属性,不是变量,只有变量才会有作用域这一说法)
  • print() {} 内部是一个独立的函数作用域

2. 核心:JS 变量查找规则 = 作用域链查找(和 this 无关)

当你在函数里写:
console.log(msg);
 
JS 引擎会按照作用域链一层层找变量 msg
  1. 先找 print 函数自身作用域 → 没有
  2. 再找 类的私有 / 块级作用域 → 类没有块级作用域,找不到
  3. 再找 全局作用域 → 还是没有
  4. 最终:抛出错误 msg is not defined

3. 关键知识点:类成员变量 ≠ 局部变量

很多新手最容易踩坑的点:

❌ 错误认知

“我在类里写了 msg,所以类里所有方法都能直接用 msg。”

✅ 正确认知

  • msg 不是变量
  • msg 是实例对象的属性,存在于 this
  • 属性不会自动加入作用域
  • 作用域只查找变量,不查找对象属性

4. 对比:为什么必须写 this.msg 才正确?

print() {console.log(this.msg); // 正确
}
 
这里发生了两件完全不同的事:
  1. this 是通过执行上下文确定的对象(p 对象)
  2. this.msg 是访问对象的属性,不是作用域变量查找
一个是对象属性访问,一个是作用域变量解析完全是两套机制

5. 用最通俗的话总结作用域问题

你可以把作用域想象成房间
  • 类的 {} 不是一个房间
  • 每个方法 {} 才是一个独立房间
  • msg 根本没放在房间里,而是贴在实例对象身上
  • 你在房间里大喊 msg,当然找不到

6. 最终结论(深度版)

作用域角度看:
  1. ES6 class 没有类作用域,只有方法级函数作用域(注意:这个也是理解的重点)
  2. 类字段 msg实例属性,不是作用域变量
  3. print 内部执行 console.log(msg) 时,JS 只会沿着作用域链查找变量
  4. 作用域链中不存在 msg 变量,因此抛出 not defined
  5. 必须用 this.msg 访问属性,这属于对象属性访问,与作用域无关

7. 修正后的正确代码

class Person {msg = "底层原理";print() {// 必须通过 this 访问实例属性console.log(this.msg); }
}const p = new Person();
p.print(); // 输出:底层原理
 

总结

  1. 作用域查找变量,对象访问属性
  2. 类成员变量是属性,不是变量,不会进入作用域
  3. 方法内部直接写 msg → 作用域找不到 → 报错
  4. 方法内部写 this.msg → 访问实例属性 → 正确
这就是 JS 类最经典、最核心的作用域与 this 面试题之一。

注:下一篇中我们会讲到类中,也就是class中,为什么不能使用avr a = 123;或let a =123;的具体原因。与本篇还是有着紧密的联系的。

 

http://www.rkmt.cn/news/1303356.html

相关文章:

  • 如何彻底解决学术论文PDF翻译的格式难题?BabelDOC完整指南
  • 如何用UnrealPakViewer透视虚幻引擎Pak文件的内部世界?
  • PowerPoint中的LaTeX魔法:让专业公式编辑变得如此简单
  • 专业视频资源捕获指南:猫抓扩展的完整高效解决方案
  • Android应用安全加固实战:JoySafeter开源框架深度解析与集成指南
  • Dream-Creator:开源AI图像生成工具部署与核心功能实战指南
  • PDF翻译格式错乱终结者:BabelDOC如何完美保持原格式
  • Meta SAM模型实战避坑指南:从安装、提示工程到与YOLOv8联调,一次讲清
  • 3个技巧彻底解放你的FGO时间:Fate/Grand Automata自动化实战指南
  • Applite终极教程:免费开源macOS软件管家,告别命令行烦恼
  • 词达人自动化助手终极指南:3分钟完成30分钟词汇任务的完整教程
  • 3步打造智能NAS影视库:MoviePilot自动化管理终极指南
  • 如何快速掌握yfinance:从零到实战的Python金融数据获取终极指南
  • ViGEmBus终极指南:Windows游戏控制器模拟驱动完全解析
  • 深入Transformer内部:LoRA到底改动了哪部分权重才让模型“学会”新任务?
  • Kafka运维新选择:Offset Explorer(Kafka Tool)在Windows下的详细评测与实战技巧
  • CircuitPython与NeoPixel打造3D打印龙形灯:嵌入式开发与数字制造实践
  • 免费额度即将失效?ElevenLabs 2024.6.1新规生效前,必须完成的5项额度迁移准备
  • 游戏开发区域加载系统:核心设计、状态机与性能优化实践
  • 终极城通网盘解析指南:如何免费获得40倍下载速度
  • 如何用ContextMenuManager管理工具彻底优化Windows右键菜单使用体验?
  • 终极Python通达信数据解析方案:mootdx完整使用指南与金融量化实践
  • WorkshopDL终极指南:免费下载Steam创意工坊模组,轻松打破平台限制
  • 城通网盘下载终极指南:告别限速,3步获取高速直连地址!
  • Docker 容器化部署:从手动运维到一键发布,我踩过的 7 个坑
  • 一种用于并网光伏系统的创新型多层逆变器,以降低总谐波失真(THD)研究(Matlab代码实现)
  • 如何用AzurLaneAutoScript实现游戏自动化:完整高效解决方案
  • 5 分钟搞定 Open Claw v2.7.1|本地 AI 智能体安装
  • 魔兽争霸III终极优化指南:用WarcraftHelper插件彻底提升游戏体验
  • 图数据库与多模态大模型融合:构建精准视觉检索增强生成系统