Proxy 是 ES6 引入的元编程特性,简单说就是给对象 “装一层拦截器”—— 所有对对象的操作(比如读属性、改属性、删属性),都会先经过这层拦截器,我们可以在拦截器里自定义操作逻辑。它的灵活性极高,是 Vue3 响应式、数据验证、API 拦截等场景的核心技术。
关联知识可以将 Proxy 和 Reflect 合并在一起学习~
Reflect:ES6 标准化对象操作的 “工具库”
Touko
一、Proxy 的核心:三要素与基础用法Proxy 的使用很直观,核心是 new Proxy(target, handler) 这个构造函数,需要传入两个关键参数:
12// 基本语法:创建一个代理对象const proxy = new Proxy(target, handler);
target:被代理的 “目标对象”(可以是普通对象、数组、函数,甚至另一个代理)。
handler:“拦截器配 ...
Reflect 是 ES6 新增的内置对象,核心作用是提供一套统一、函数式的对象操作 API。它的方法与 Proxy 拦截器一一对应,既能替代传统的对象操作方式(如 delete、in),又能解决旧语法的不一致问题,是元编程和 Proxy 配合的 “最佳搭档”。
关联知识可以将 Proxy 和 Reflect 合并在一起学习~
代理(Proxy):ES6 元编程的 “对象拦截器”
Touko
一、为什么需要 Reflect?—— 解决旧语法的痛点在 Reflect 出现前,JavaScript 操作对象的方式很 “零散”,存在三个明显问题:
操作形式不统一:有的是关键字(如 delete obj.prop、prop in obj),有的是 Object 上的方法(如 Object.keys(obj)、Object.defineProperty()),风格混乱。
错误处理不一致:有的操作失 ...
async/await 是 ES2017 引入的强大特性,使得处理异步操作变得更加简单和直观。使用 async 声明的函数总是返回一个 Promise,而 await 关键字则像是它的指挥棒,允许你暂停函数的执行,直到 Promise 被解决或拒绝。这种方式让异步代码看起来更像同步代码,从而提高了可读性和可维护性。尤其在处理链式异步操作和错误捕获时,async/await 显示出其独特的优势。
前置知识如果对生成器函数和 yield 不太熟悉,可以先看看下面这篇,了解基础后再看 Async / Await 会更顺~
生成器函数与 yield
Touko
一、Async / Await 的本质:老熟人的默契配合你可能觉得 Async / Await 是 JavaScript 里的 “新黑科技”,但其实它的底层是三个老熟人在搭班子干活。说穿了,就是把咱们早就眼熟的技术组合得更顺手了。
1.1 ...
生成器函数是 ES6 里很实用的特性,而 yield 就像给函数装了个 “暂停开关”—— 能让函数执行到一半停下来,需要的时候再接着跑。这种 “可控的执行流程”,在处理异步操作、遍历大数据、实现状态切换时特别好用。
一、生成器:能 “中场休息” 的特殊函数1.1 什么是生成器函数?生成器函数是可以暂停执行、后续恢复的特殊函数,它的语法很容易识别:用 function* 定义,内部用 yield 控制暂停。
举个最简单的例子,感受下它的 “暂停 - 恢复” 能力:
1234567891011121314// 用 function* 定义生成器函数function* stepGenerator() { yield '第一步:准备'; yield '第二步:执行'; return '第三步:完成'; // return 的值会作为最后一次 next() 的 value}// 调用生成器函数:不会立即执行,而是返回一个“生成器对象”(类似控制器)const generator = stepGenerator();// 调用 next() 恢复执行,直到遇到下一个 yield 或 re ...
MessageChannel 是浏览器提供的点对点双向通信 API,核心是创建一对关联的 “通信端口”(port1 和 port2),让不同上下文(比如主线程与 Worker、父页面与 iframe)能安全、高效地传递消息。它不像全局事件那样容易污染,也比普通 postMessage 更专注于 “一对一” 通信场景。
一、核心概念:从创建到通信的基本流程MessageChannel 的用法很直观:先创建通道,拿到两个端口,再通过端口的 postMessage 发消息、onmessage 收消息,形成双向通信链路。
12345678910111213141516171819202122// 1. 创建一个 MessageChannel 实例(相当于建立一条通信管道)const channel = new MessageChannel();// 2. 从管道中获取两个相互关联的端口(port1 和 port2 是“一对”)const port1 = channel.port1;const port2 = channel.port2;// 3. 端口1 发送消息(可传字符串、对象等结构化 ...
迭代器是 JS 统一数据遍历的 “通用接口”,解构则是简化数据提取的 “语法糖”—— 两者结合能让你更优雅地处理数组、对象、DOM 集合等各种数据结构。这篇文章从原理到实战,带你吃透这两个高频用到的核心特性。
一、迭代器:统一数据遍历的 “通用接口”1.1 什么是迭代器?迭代器本质是一套 标准化协议(Iterator Protocol),定义了 “如何按顺序访问数据集合” 的规则。简单说:只要一个对象实现了这套协议,就能用统一的方式(比如 for...of)遍历,不管它是数组、字符串还是自定义对象。
举个生活化的例子:你有一个文件夹,里面有多个文件。迭代器就像一个 “文件读取器”—— 它记住当前读到哪个文件,每次告诉你 “下一个文件是什么”,直到所有文件读完。
看个自定义迭代器的实现,理解它的核心逻辑:
123456789101112131415161718192021222324252627282930// 模拟一个“文件夹”对象,里面有多个“文件”const folder = { files: ['笔记.txt', '照片.jpg', '文档.pdf'], // 实现迭代器 ...
在 JavaScript 的世界里,事件就像网页的 “交互信号”—— 用户点击按钮、滚动页面、输入文字,都是通过事件让网页做出反应。今天我们从基础到进阶,把浏览器事件机制拆解开,再聊聊怎么用得更高效,避免常见的性能坑!
一、事件系统:网页的 “交互逻辑骨架”1.1 事件流三阶段:从顶层到目标,再回到顶层事件触发后,不是直接定位到目标元素,而是会经历 “捕获 → 目标 → 冒泡” 三个阶段,就像水流先向下流到目标,再向上回流:
graph LR
A[捕获阶段] --> B[目标阶段] --> C[冒泡阶段]
style A fill:#4CAF50,stroke:#388E3C
style B fill:#2196F3,stroke:#1976D2
style C fill:#FF9800,stroke:#F57C00
捕获阶段 (Capture Phase):事件从 window 开始,顺着 DOM 树向下传递,直到目标元素的父级(比如点击按钮时,先经过 body、div,再到按钮的父元素)
目标阶段 (Target Phase):事件终于到达触发的目标元 ...
原型链是 JavaScript 面向对象的 “底层逻辑”—— 它让对象能 “继承” 其他对象的属性和方法,而 ES6 的 class 只是这套逻辑的 “语法糖”。今天从原型链的本质讲到 Class 的应用,帮你彻底搞懂 JS 继承到底是怎么回事。
一、原型链:JS 对象继承的 “底层骨架”1.1 什么是原型链?简单说,原型链是 JS 实现继承的核心机制:每个对象都有一个隐藏的 “原型”([[Prototype]],可通过 Object.getPrototypeOf() 访问),这个原型本身也是一个对象,它也有自己的原型 —— 这样层层向上,就形成了一条 “原型链”。
当你访问一个对象的属性时,如果当前对象没有这个属性,JS 会自动沿着原型链向上查找,直到找到属性或走到链的尽头(null)。
看个直观的例子:
1234567891011// 父对象:动物,有一个共享属性 eatsconst animal = { eats: true };// 子对象:兔子,有自己的属性 jumpsconst rabbit = { jumps: true };// 把 rabbit 的原型设为 ani ...
闭包是 JavaScript 中比较容易让人困惑的概念 —— 它能让函数 “记住自己成长的环境”,哪怕后来跑到别的地方工作,也能找回当初的变量。今天就抛开复杂术语,用更通俗的方式拆解闭包,从原理到实战一次讲明白!
前置知识如果对作用域链还不熟悉,建议先看下面这篇。理解函数如何查找变量后,再理解闭包会更顺畅~
作用域链(Scope Chain)
Touko
一、闭包的本质:函数 + 诞生环境1.1 到底什么是闭包(Closure)?官方定义有点抽象:闭包是函数与其声明时所在词法环境的组合。
换成人话就是:一个函数在 “老家”(声明时的作用域)定义时,记下了周围的变量;后来就算跑到 “外地”(其他作用域)执行,也能找到这些 “老家的变量”—— 这就形成了闭包。
举个直观的例子,你看这个 “带记忆的函数”:
1234567891011121314function createMemory() { ...
作用域链是 JavaScript 查找变量的核心机制 —— 当代码需要访问一个变量时,JS 引擎会沿着 “当前作用域 → 父作用域 → 全局作用域” 的顺序层层查找,这条查找路径就像一张 “路线图”,指引引擎找到目标变量。
一、作用域链的本质:静态的查找路径1.1 核心概念:从 “作用域” 到 “作用域链”首先要明确:作用域是变量的 “可访问范围”(比如函数内部的变量只能在函数内访问),而 “作用域链” 是多个嵌套作用域组成的 “查找链条”。
比如函数嵌套场景,内部函数会形成包含父函数作用域、祖父函数作用域的链条,最终指向全局作用域:
graph LR
A[当前作用域(如 inner 函数)] --> B[父作用域(如 outer 函数)]
B --> C[祖父作用域(更外层函数)]
C --> D[...]
D --> E[全局作用域]
1.2 关键特性:作用域链 “定义时确定,而非调用时”这是理解作用域链的核心 —— 函数的作用域链在函数定义的那一刻就固定了,和函数什么时候调用、在哪里调用无关。这个特性也是闭包(👉 闭包(Closure): ...











