Es6之代理与模块
Proxy代理对象
在学习之前我们需要了解一下什么是proxy
Proxy(代理)是 ES6 中引入的一个非常强大的特性,它允许你创建一个对象的“代理”,从而可以拦截并重新定义该对象的基本操作(如属性查找、赋值、枚举、函数调用等)。
你可以把它理解为一个对象的“中介”或“包装器”。所有对目标对象的操作,都不会直接作用到对象本身,而是先经过这个“中介”。这个“中介”可以决定如何以及是否将操作转发给原始对象。
我举个例子你就知道了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./main.js"></script>
<link rel="stylesheet" href="main.css">
<link rel="shortcut icon" href="#"/>
</head>
<body>
<div id="app">1111</div>
</body>
</html>
这是一个很简单的页面 只显示了一个1111
在我引用的main.js文件 我这样子写
const obj = {
name:'pzt',
age = '19'
}
const app = document.getElementById('app')
app.textContent = obj.name
那么现在因为我写了这一段js index页面就会把1111改成pzt
那么现在当我修改了obj的name时
obj.name = 'zx'
但是我修改完后 index页面还是呈现的是pzt
所以我只能再加上一句
app.textContent = obj.name
才能使得index页面呈现zx
但是在现实中这样子就太麻烦了 我总不可能每一次修改名字后都要加上这么一句吧
那么这个时候 proxy代理对象的作用就体现出来了 我可以创建一个proxy来代理obj这个对象 然后在该proxy中添加我想要的效果 比如我想让index页面在我修改完名字之后显示最新的名字 我就可以在该proxy中添加这一句话
app.textContent = obj.name
就可以使得每次我修改name时都会自动执行该命令 多说无益 直接上代码解释
但是首先你要了解proxy的基本语法
创建一个 Proxy 需要两个参数:
- target(目标对象): 要被代理的原始对象。
- handler(处理器对象): 一个定义了哪些操作将被拦截以及如何重新定义这些操作的对象。处理器对象内部可以包含一系列可选的“捕获器”(trap)方法,比如
get,set,has等
const target = {
message: "hello, world"
};
const handler = {
get(target, prop, receiver) {
return ` intercepted get: ${target[prop]}`;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message); // 输出: intercepted get: hello, world
console.log(target.message); // 输出: hello, world (原始对象不受影响)
在上面的例子中,当我们通过 proxy 访问 message 属性时,handler 中的 get 捕获器被触发,它拦截了这次读取操作并返回了我们自定义的值。而直接访问原始 target 对象则不受影响。
常见的捕获器 (Trap)
处理器对象 handler 可以定义的方法非常多,这里列举一些最常用的:
| 捕获器名称 | 对应的操作 | 触发条件 |
|---|---|---|
get | [[Get]] | 读取属性,如 proxy.property |
set | [[Set]] | 设置属性,如 proxy.property = value |
has | [[HasProperty]] | in 操作符,如 'property' in proxy |
deleteProperty | [[Delete]] | delete 操作符,如 delete proxy.property |
apply | [[Call]] | 函数调用,如 proxy(...args) |
construct | [[Construct]] | new 操作符,如 new proxy(...args) |
getPrototypeOf | [[GetPrototypeOf]] | Object.getPrototypeOf(proxy) |
setPrototypeOf | [[SetPrototypeOf]] | Object.setPrototypeOf(proxy) |
ownKeys | [[OwnPropertyKeys]] | Object.keys(proxy), Object.getOwnPropertyNames() |
我直接复制了官方文档的一些内容下来给你看 你可能有些蒙蒙的 没事 我以刚刚修改名字的那个例子给你讲解一遍
const obj = {
name : 'pzt',
age : 18
}
//这里写你要让p1代理的目标(就是这个obj)
const p1 = new Proxy(obj,{
//这里要注意target就是obj 但是你只能写出target
//prop就是该目标的属性
//receiver是最初调用该属性的对象,决定了函数中 this 的指向
get (target , prop , receiver){
return target[porp]
},//get就是我刚刚所展现给你看的捕获器
//注意 这里的value参数表示要赋给属性的新值 它就是等号右边的值
set(target , prop , value ,receiver){
target[porp] = value
app.textContent = obj.name//看见没 最关键的来了 我刚刚是不是想让他实时更新最新的 属性 那么将捕获器捕获到你要修改的步骤时 他会执行这个set函数 所以就可以在index页面呈现我想要的效果
}
})
p1.name = 'zx'//注意 这个时候修改的时候就不要直接用obj.name = 'zx' 这样子进行修改 你要使用 p1这个已经代理obj对象的Proxy实例来修改 才能有效
这个时候index页面就会呈现
zx
这个时候你可能会说 哎呀不就整个更新名字吗 有必要那么麻烦吗 我就想跟上面那样直接写一句话就行了还整这些 不 兄弟 你在业务中会遇到那么简单的逻辑吗 我只是为了方便让你懂才这样 所以学习这个是很必要的
Module模板
首先我们了解一下这个是什么意思
模块是 JavaScript 中一个非常重要的概念,它允许你将代码分割成独立的功能单元,每个单元拥有自己的作用域,并且可以导出(export)特定的变量、函数或类供其他模块使用,也可以导入(import)其他模块提供的功能。
通俗地来讲呢 你就想象一下 一个js模块 就是一个装满工具的工具箱
- 你的代码文件(比如
myTools.js):就是一个工具箱。 - 里面的函数和变量(比如
hammer,screwdriver):就是箱子里的工具。 export(导出):就是在箱子上贴个清单,告诉别人这个箱子里有什么工具可以借给别人用。import(导入):就是你看到清单,去别人的箱子里把工具拿过来给自己用
1. 怎么把工具借出去?(Export 导出)
情景一:现场贴标签(声明时直接导出) 你在造工具的时候,直接就贴上“可外借”的标签。
// myTools.js 工具箱
export const hammer = "🔨 锤子"; // 造了个锤子,直接标明可外借
export function screwdriver() { // 造了个螺丝刀,直接标明可外借
return "🪛 螺丝刀";
}
情景二:最后统一列清单(最后统一导出) 你先在箱子里把工具都造好,最后再统一列一个清单。
// myTools.js 工具箱
const hammer = "🔨 锤子"; // 造了个锤子,先放箱子里
const screwdriver = () => "🪛 螺丝刀"; // 造了个螺丝刀,先放箱子里
// 最后,列一个清单,写上哪些工具可以借
export { hammer, screwdriver };
情景三:镇箱之宝(默认导出) 一个工具箱里,可以有一个最常用、最主要的“镇箱之宝”。别人来借的时候,不用指定名字,直接说“我要借你的镇箱之宝”就行。
// myTools.js 工具箱
const powerDrill = "🪚 电钻"; // 这是我最牛的工具
// 把它设为“镇箱之宝”
export default powerDrill;
// 你也可以外借其他普通工具(命名导出)
export const hammer = "🔨 锤子";
记住:一个工具箱里,只能有一个“镇箱之宝”(默认导出)。
2. 怎么去借工具?(Import 导入)
情景一:借特定的工具(按名字借) 你看到别人工具箱的清单,只借你需要的那个工具。必须用 {} 包起来。
// myProject.js 我的项目
import { hammer } from './myTools.js'; // 从myTools箱子里只借hammer
console.log(hammer); // 使用借来的锤子
// 输出: "🔨 锤子"
你可以一次借多个:
import { hammer, screwdriver } from './myTools.js';
情景二:借“镇箱之宝”(默认导入) 借镇箱之宝最简单,不用记名字,也不用 {}。你可以随便给它起个名字。
// myProject.js 我的项目
import MyMainTool from './myTools.js'; // 把“镇箱之宝”借过来,我管它叫MyMainTool
console.log(MyMainTool); // 使用电钻
// 输出: "🪚 电钻"
情景三:把整个工具箱都搬过来
如果你需要很多工具,可以干脆把整个箱子都搬过来,然后用 箱子.工具名 的方式来用。
// myProject.js 我的项目
import * as ToolBox from './myTools.js'; // 把整个myTools箱子搬过来,我管这个箱子叫ToolBox
console.log(ToolBox.hammer); // 用箱子里的锤子
console.log(ToolBox.screwdriver()); // 用箱子里的螺丝刀
情景四:既借镇箱之宝,也借普通工具
// myTools.js 工具箱里有:默认导出的 powerDrill 和命名导出的 hammer
import MyDrill, { hammer } from './myTools.js';
// MyDrill 是镇箱之宝(电钻),{ hammer } 是普通工具(锤子)
为什么要用模块?(好处)
- 不打架:每个工具箱里的工具都是自己私有的,就算你和别人都有叫“hammer”的工具,也不会冲突。避免了“全局变量污染”。
- 好管理:代码变得非常有条理。工具(功能)都分门别类放在不同的箱子(文件)里,找起来方便。
- 可复用:写好一个工具箱(比如一个数据处理模块),可以在很多个项目里重复使用,不用重复造轮子。
- 安全:工具箱里你没答应外借 (
export) 的工具,别人是拿不走的,是私有的。
在网页里怎么用?
在 HTML 里引入你的主模块文件时,要加上 type="module" 这个属性,告诉浏览器:“这是个模块哦!”
html
<script type="module" src="myProject.js"></script>
重要提醒:带有 type="module" 的脚本不能直接用浏览器打开本地文件(file:// 协议),需要一个简单的本地服务器(比如 VSCode 的 Live Server 插件)。
好了 这就是全部内容了 希望你可以在学习的道路上不断前行 加油!!!