【JavaScript】JS 核心:原型链、继承、闭包、作用域、执行上下文、this 指向、call/apply/bind(附《思维导图》)

简介: 本文系统梳理JS七大核心概念:执行上下文、作用域、闭包、this、call/apply/bind、原型链与继承,从运行机制、变量访问、执行主体、对象模型四大维度揭示其内在关联与底层逻辑,构建完整知识图谱。

思维导图

JavaScript 核心知识体系全景总结

以下从运行机制、变量访问、执行主体、对象模型四大维度,系统性梳理原型链、继承、闭包、作用域、执行上下文、this指向、call/apply/bind 七大核心概念,并明确各知识点的内在关联与底层逻辑。


一、执行上下文:代码运行的环境基石

核心定义:JavaScript 引擎执行代码时的运行环境单元,包含代码执行所需的全部信息(变量、函数、作用域链、this 等),是 JS 运行机制的最小单位。

1. 三类执行上下文

  • 全局执行上下文:程序启动时唯一创建,全局代码均在此环境运行。浏览器中对应 window,Node 中对应 globalThis。
  • 函数执行上下文:函数被调用时动态创建,每次调用生成独立的新上下文。
  • Eval 执行上下文:eval() 函数执行时创建,存在安全与性能问题,工程中极少使用。

2. 执行栈(调用栈)

  • 遵循后进先出(LIFO)原则,管理所有执行上下文的生命周期。
  • 程序启动时全局上下文入栈;函数调用时函数上下文入栈;函数执行完毕后上下文出栈,控制权回到上一层。

3. 执行上下文的生命周期

分为创建阶段和执行阶段两个步骤:

(1)创建阶段(函数调用后、代码执行前)

  1. 变量对象(VO):收集当前上下文中的变量声明、函数声明、形参。函数上下文中的变量对象称为活动对象(AO),进入执行阶段后激活。

    变量提升、函数提升的本质:创建阶段 VO 已完成声明收集,因此代码执行前即可访问声明。

  2. 作用域链:由当前 AO 与上层上下文的 VO 组成,负责变量查找。
  3. this 绑定:确定当前上下文的 this 指向。

(2)执行阶段

完成变量赋值、函数引用与逐行代码执行;执行完毕后上下文出栈,等待垃圾回收。


二、作用域与作用域链:变量访问的静态规则

核心定义:作用域是变量和函数的可访问范围,是一套静态语法规则,在代码定义时就已确定,与执行位置无关。

1. 三类作用域

  • 全局作用域:最外层作用域,全局变量随处可访问,页面关闭才销毁。
  • 函数作用域:函数内部声明的变量仅在函数内部可访问,外部无法直接读取。
  • 块级作用域(ES6):由 {} 包裹,通过 let/const 声明的变量仅在当前代码块内生效,存在暂时性死区(TDZ),不存在变量提升。

2. 词法作用域(静态作用域)

JavaScript 采用词法作用域:函数的作用域在函数定义时就已固化,和调用位置、调用方式无关。与之相对的是动态作用域(如 bash 脚本),作用域在调用时才确定。

3. 作用域链

  • 定义:访问变量时,JS 引擎从当前作用域开始,逐级向上追溯上层作用域,直到全局作用域,这个链式查找结构就是作用域链。
  • 查找规则:就近原则,内层可访问外层,外层不可访问内层;同名变量内层覆盖外层。
  • 本质:作用域链是执行上下文的核心组成部分,其结构由词法作用域静态决定。

三、闭包:作用域与生命周期的交叉产物

核心定义:闭包是函数与其词法作用域的组合。当内部函数引用了外部函数的变量,且内部函数在外部函数执行完毕后依然存活(被返回/被外部持有),就形成了闭包。

1. 形成闭包的三个必要条件

  1. 函数嵌套函数;
  2. 内部函数引用外部函数的变量或参数;
  3. 内部函数被返回或被外部环境持有(如赋值给全局变量、作为回调函数)。

2. 闭包的底层本质

外部函数执行完毕后,其执行上下文会出栈,但外部函数的活动对象(AO)不会被垃圾回收——因为内部函数的作用域链仍然持有对它的引用。

3. 典型应用场景

  1. 数据私有化/模块化:模拟私有变量,避免全局污染
    function createCounter() {
         
      let count = 0;
      return {
         
        increment: () => count++,
        getCount: () => count
      };
    }
    
  2. 函数柯里化:参数复用、延迟执行;
  3. 防抖与节流:保存上一次执行的状态;
  4. 循环变量保留:解决 var 声明下循环变量共享作用域的问题。

4. 注意事项

  • 内存泄漏风险:闭包会长期持有外部作用域引用,若不当使用(如循环引用、持有大对象)会导致内存无法释放;
  • 箭头函数同样可以形成闭包,且其 this 继承自外层词法作用域。

四、this 指向:执行上下文的动态主体

核心定义:this 是执行上下文的内置属性,指向当前代码的执行主体。this 的指向在函数调用时动态确定,与函数定义位置无关。

1. 六大场景的 this 指向

调用场景 this 指向 补充说明
全局环境直接执行 全局对象(浏览器 window / Node globalThis) 严格模式下为 undefined
普通函数直接调用 全局对象 严格模式下为 undefined
对象方法调用 调用该方法的对象 谁调用,就指向谁
构造函数调用(new) 新创建的实例对象 new 会创建空对象并绑定 this
箭头函数 定义时外层词法作用域的 this 无自身 this,不可被修改
DOM 事件处理函数 绑定事件的 DOM 元素 addEventListener 回调默认指向元素

2. new 操作符的执行过程

  1. 创建一个全新的空对象;
  2. 将空对象的 __proto__ 指向构造函数的 prototype;
  3. 将构造函数的 this 绑定到该空对象;
  4. 执行构造函数内部代码;
  5. 若构造函数返回对象则返回该对象,否则返回这个新对象。

3. this 绑定优先级(从高到低)

new 绑定 > bind 绑定 > call/apply 绑定 > 对象方法调用 > 默认绑定(普通函数调用)

4. 箭头函数的 this 特性

  • 没有自身的 this、prototype、arguments,不能作为构造函数;
  • this 继承自定义时外层作用域的 this,且无法通过 call/apply/bind 改变。

五、call / apply / bind:this 的手动控制

三者都是 Function.prototype 上的原生方法,核心作用是手动修改函数内部的 this 指向,是 this 动态绑定的核心 API。

1. 三者核心对比

方法 执行时机 参数形式 返回值 核心特点
call(thisArg, arg1, arg2, ...) 立即执行 参数逐个传递 函数执行结果 改变 this 并立即调用
apply(thisArg, argsArray) 立即执行 参数以数组/类数组传递 函数执行结果 适合参数数量不确定的场景
bind(thisArg, arg1, arg2, ...) 不立即执行,返回新函数 参数可分批传递(柯里化) 绑定了 this 的新函数 永久绑定 this,支持延迟执行

2. 关键注意点

  • 若 thisArg 传入 null/undefined,非严格模式下 this 会指向全局对象,严格模式下为传入的值;
  • 箭头函数调用三者无效,无法修改其 this;
  • 多次 bind 只有第一次生效,后续绑定不会覆盖。

3. 经典应用场景

  1. 类数组借用数组方法:Array.prototype.slice.call(arguments);
  2. 构造函数继承:子类构造函数中借调父类构造函数;
  3. 精准判断数据类型:Object.prototype.toString.call(obj);
  4. 固定回调 this:如 React 类组件事件回调绑定。

六、原型与原型链:对象的属性查找机制

核心定义:原型是 JavaScript 实现面向对象的核心机制,原型链是对象属性/方法的查找规则,也是继承的底层基础。

1. 核心概念与三角关系

所有对象与函数都遵循原型三角关联:

  1. 构造函数:用于创建对象的函数,自带 prototype 属性;
  2. 原型对象:构造函数 prototype 指向的对象,用于存放所有实例共享的属性和方法;
  3. 实例对象:通过 new 构造函数创建的对象,自带 __proto__(内部属性 [[Prototype]]),指向构造函数的原型对象;
  4. constructor 属性:原型对象的 constructor 指回对应的构造函数。

核心公式:

实例.__proto__ === 构造函数.prototype
构造函数.prototype.constructor === 构造函数

2. 原型链

  • 定义:原型对象本身也是普通对象,同样拥有自己的 __proto__,指向其构造函数的原型;层层向上追溯,直到 Object.prototype.__proto__ === null,这条链式结构就是原型链。
  • 属性查找规则:访问对象属性时,先查找对象自身;找不到则沿 __proto__ 向上遍历原型链;到顶端仍未找到则返回 undefined。
  • 属性遮蔽:对象自身属性与原型属性同名时,优先读取自身属性。

3. 标准 API 与误区

  • __proto__ 是浏览器实现的非标准属性,工程中推荐使用:
    • Object.getPrototypeOf(obj):获取对象原型
    • Object.setPrototypeOf(obj, proto):设置对象原型
  • 所有函数的默认原型都是 new Object(),因此原型链最终都会指向 Object.prototype。

七、继承:基于原型链的代码复用方案

JavaScript 的继承本质是基于原型链的代码复用,经历了多个演进阶段,最终形成成熟的最优方案。

1. 七种继承方案演进

(1)原型链继承

  • 实现:Child.prototype = new Parent()
  • 缺陷:父类引用属性被所有子类实例共享;创建子类时无法向父类传参。

(2)构造函数继承(借调)

  • 实现:子类构造函数内执行 Parent.call(this, ...args)
  • 优点:可传参、避免引用共享;
  • 缺陷:只能继承实例属性,无法继承父类原型方法,方法无法复用。

(3)组合继承

  • 实现:原型链继承方法 + 构造函数继承属性
  • 缺陷:调用两次父类构造函数,子类原型上存在多余的父类实例属性。

(4)原型式继承

  • 实现:基于已有对象创建新对象,对应 ES6 Object.create()
  • 缺陷:引用属性仍然被所有新对象共享。

(5)寄生式继承

  • 实现:在原型式基础上封装函数,为对象新增方法
  • 缺陷:方法无法复用,每个对象都有独立副本。

(6)寄生组合式继承(ES5 最优方案)

  • 核心:子类原型继承父类原型的副本,不重复调用父类构造函数
    function inherit(Child, Parent) {
         
      const proto = Object.create(Parent.prototype);
      proto.constructor = Child;
      Child.prototype = proto;
    }
    
  • 优势:仅调用一次父类构造函数,无冗余属性,完整保留原型链结构。

(7)ES6 Class 继承(语法糖)

  • 语法:class Child extends Parent { constructor() { super(); } }
  • 本质:底层仍然是寄生组合式继承,super() 对应构造函数借调,extends 对应原型链关联。
  • 特性:class 必须通过 new 调用,无变量提升;静态方法通过 static 声明,继承自父类本身。

八、知识体系整体关联

  1. 底层运行层:执行上下文是代码运行的最小环境单元,执行栈管理生命周期;每个上下文包含变量对象、作用域链、this 三大核心要素。
  2. 变量访问层:作用域是静态语法规则,决定作用域链的结构;闭包是作用域与执行上下文生命周期不一致的产物,让函数可以“记住”定义时的环境。
  3. 执行主体层:this 是执行上下文的动态属性,由调用方式决定;call/apply/bind 提供了手动控制 this 的能力。
  4. 对象模型层:原型链是对象的属性查找机制,是 JS 面向对象的核心;从原型链到 ES6 Class,本质都是基于原型的代码复用。
相关文章
|
1月前
|
存储 弹性计算 负载均衡
阿里云服务器可以免费试用吗?当然可以,云服务器ECS试用攻略参考
本文是一份面向阿里云ECS新用户的免费试用全流程实用攻略,明确了参与试用的核心门槛:完成实名认证、未付费或未试用过ECS且账号无欠费。个人认证用户可领取300元总免费额度,企业认证用户可领取660元总免费额度,二者均附带每月220GB公网免费流量,整体试用有效期3个月。攻略详细说明了多台实例、跨地域试用的操作方法,梳理了从单台应用托管到多台高可用集群的典型适用场景,同时汇总了额度查询、超支规避、到期衔接等高频问题的解决方案,帮助用户在零成本前提下充分体验云服务器的弹性能力,试用结束后还可平滑衔接平台特惠实例方案。
|
1月前
|
人工智能
Qoder 实训营上线!每周四两小时,一期拆一个真实卡点
你是否也遇到AI生成代码“看似正确却不敢合入主干”的困境?本实训营直击真实卡点,每周四16:00–18:00,手把手带你厘清AI编码的落地边界、验收标准与协作规范,让AI真正融入核心开发流程。
210 0
Qoder 实训营上线!每周四两小时,一期拆一个真实卡点
|
1月前
|
弹性计算 小程序 测试技术
阿里云服务器可以免费试用吗?个人企业均可试用,手把手看懂免费试用
本文是一份通俗易懂的阿里云ECS免费试用核心规则解读指南,针对用户最关心的四大关键问题做了清晰拆解。个人用户可领取300元免费额度,企业用户可领取660元免费额度,二者均受3个月有效期与额度余额的双重约束,任一条件触发即试用终止。个人可试用e/u1实例、最高4核8G,企业可在此基础上额外试用c7/g7/r7等实例、最高8核16G。同时明确了个人每小时0.833元、企业每小时1.833元的消费上限,以及“创建即计费、停机仍计费、释放才停计费”的核心扣费逻辑。全文用生活化比喻降低理解门槛,提醒用户及时释放闲置实例,避免超额度产生欠费。
|
7天前
|
存储 安全 虚拟化
VMware 【13】设置非永久磁盘,验证关机后的数据变化
杨利杰YJlio的个人技术主页,专注Windows系统疑难排查、Sysinternals工具实战、PowerShell自动化及Python办公提效。本教程详解VMware Workstation“非永久磁盘”配置与验证,助你理解虚拟磁盘还原机制,实现安全可控的实验环境。(239字)
59 2
|
1月前
|
人工智能 自然语言处理 监控
不止降本增效:AI智能客服如何成为企业业务增长新引擎
瓴羊Quick Service是阿里云推出的企业级智能客服平台,融合大模型与AI Agent技术,实现从“被动应答”到“主动服务+任务执行”的跃迁。支持多渠道接入、多模型灵活切换,AI问答准确率达93%,可自动查物流、改地址、催发货等,助力企业降本增效、转化销售、驱动决策,真正将客服升级为“增长引擎”。
|
1月前
|
JavaScript 前端开发 API
【JavaScript】事件循环 Event Loop:宏任务 vs 微任务、浏览器 vs Node.js Event Loop(附《思维导图》)
JavaScript事件循环是单线程异步编程的核心机制,通过宏任务与微任务分层调度,协调调用栈与任务队列。浏览器侧重渲染流畅性,Node.js聚焦IO高效处理,二者在阶段模型、任务类型及优先级上存在本质差异。
|
2月前
|
人工智能 测试技术 Shell
Opencode最被低估的6个测试指令:每天帮你省下3小时重复劳动
本文详解Opencode六大自定义指令(如/test、/coverage),助测试工程师30分钟配置、每日省3小时,告别重复Prompt输入,实现测试流程自动化提效。
|
1月前
|
缓存 前端开发 JavaScript
【JavaScript】异步编程:Promise、async/await、Generator、异步并发控制(附《思维导图》)
本文系统梳理JavaScript异步编程知识体系,涵盖单线程事件循环机制、回调函数→Promise→Generator→async/await四代演进、并发控制(all/race/allSettled/any)、限流取消等工程实践,助你深入原理、规避误区、提升代码质量。
|
1月前
|
人工智能 关系型数据库 Go
一条命令给 Claude Code 加上团队记忆
ContextDB 是面向编程 Agent 的轻量级上下文数据库,3 分钟 CLI 接入,无需改业务代码。支持多 Agent 共享记忆,自动沉淀技术栈、Bug 修复与团队知识,提升准确率至 79%,Token 成本降为 LightRAG 的 1/3。
129 1
|
1月前
|
测试技术 BI 分布式数据库
PolarDB-X 分布式 JOIN Benchmark:Broadcast Join 与 Shard Join 性能实测
阿里云瑶池数据库旗下的 PolarDB-X 通过 Broadcast Join(延迟 50ms)、Shard Join(QPS 92 万)和 Sort-Merge Join 三大策略,配合 CBO 自动优化器(准确率 95%)和全局二级索引(加速 23~41 倍),实现了跨库 JOIN 性能 10~50 倍的飞跃。10000+ 企业客户的实战验证了 PolarDB-X 作为分布式 JOIN 首选和最佳方案的地位,是大规模关联查询场景最值得推荐的分布式数据库。
99 0