JavaScript 的秘密生活:Proxy
Source: Dev.to
Timothy 坐在他的书桌前,看起来有点不知所措。他只有一个简单的 user 对象,但代码里到处都是 if 语句。
let user = {
name: "Timothy",
age: 25
};
// Timothy's validation code
if (user.age
“我想保护我的数据,” Timothy 轻声说道,“但我不想在每个函数里都把验证逻辑塞进对象里。有没有更简洁的办法?”
Margaret 温柔地笑了笑。她把一把椅子拉到他旁边,既不是批评者,也不是指责者,而是引导者。
“这是一种非常成熟的直觉,Timothy,”她说。“你在寻找 元编程。具体来说,是一种叫 Proxy 的工具。”
中间人
Margaret 在黑板上画了一个圆,并标记为 Target。
“通常,当你操作一个对象时,你是直接和它交互的,”她解释道。“Proxy 让你可以在该对象前放置一个‘中间人’。”
const proxy = new Proxy(target, handler);
Target 是你的原始对象。Handler 是定义规则的对象。它包含拦截你交互的 陷阱(traps)。
陷阱 1:拦截读取 (get)
“我们来做一个 harmless 的恶作剧,看看它是怎么工作的,” Margaret 说。“让引擎说谎。”
const user = { name: "Timothy" };
const handler = {
get(target, prop) {
if (prop === "name") {
return "The Great " + target[prop];
}
return target[prop];
}
};
const proxyUser = new Proxy(user, handler);
console.log(proxyUser.name); // "The Great Timothy"
Timothy 眼睛睁大了。“我并没有改变对象本身,我只是改变了读取它的方式。”
“正是如此,” Margaret 点头说。“在实际项目中,开发者会利用它来记录数据访问或创建‘私有’属性。返回什么由 Proxy 决定,而不是对象本身。”
陷阱 2:验证 (set)
“现在说说你的问题,” Margaret 温和地说。“你想阻止无效数据进入对象。我们可以使用
set陷阱。”
const validator = {
set(target, prop, value) {
if (prop === "age" && value
“没错,” Margaret 说。“你已经把 逻辑(验证器)和 数据(user)分离开来了。这正是清晰架构的标志。”
工具箱:Reflect 与其他陷阱
“它只能做到这些吗?” Timothy 问。
“远不止,” Margaret 笑道。“几乎所有操作都可以被拦截。”
has陷阱: 拦截in运算符(用于隐藏键)。deleteProperty陷阱: 防止属性被删除。apply陷阱: 拦截函数调用。
“为了让这更容易,”她补充道,“我们使用
ReflectAPI。它让我们在不手动修改目标的情况下执行默认行为。”
set(target, prop, value) {
if (value
“谢谢你,Margaret,” 他感慨道。“我感觉自己拥有了超能力。可以改变语言的行为。”
Margaret 轻拍他的肩膀。“是的,Timothy。但记住元编程的黄金法则。”
“魔法是有代价的。 Proxy 会给每一次操作带来一点性能开销。请把它们用于关键的验证,而不是系统中每一个对象。用你的力量来提升代码的清晰度,而不是制造混乱。”