Proxy 的实际应用场景
构建验证、日志记录和响应式对象。
Proxy 的实际应用场景 是 CoddyKit 上的免费 JavaScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 JavaScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 JavaScript Academy 课程共包含 4 节课。
代理对象实践
现在您将结合代理对象和 Reflect 来解决实际问题:验证、日志记录、默认值等。每种模式都会包装一个普通对象,而不修改它。
验证包装器
强制执行模式:拒绝任何不符合规则的写入。由于错误数据永远不会写入,target 可以保持整洁。
function validated(obj, rules) {
return new Proxy(obj, {
set(target, prop, value, receiver) {
const rule = rules[prop];
if (rule && !rule(value)) {
throw new TypeError('invalid value for ' + prop);
}
return Reflect.set(target, prop, value, receiver);
}
});
}
const user = validated({}, { age: v => v >= 0 });
user.age = 25;
console.log(user.age);
try { user.age = -1; } catch (e) { console.log(e.message); }日志记录包装器
在记录日志后通过 Reflect 转发操作,以跟踪每次读取和写入,便于调试。
function logged(obj) {
return new Proxy(obj, {
get(t, p, r) { console.log('GET ' + p); return Reflect.get(t, p, r); },
set(t, p, v, r) { console.log('SET ' + p + '=' + v); return Reflect.set(t, p, v, r); }
});
}
const data = logged({ count: 0 });
data.count = 5;
console.log(data.count);默认值
为任何缺失属性返回 fallback,因此读取结果不会是 undefined。
function withDefault(obj, fallback) {
return new Proxy(obj, {
get(t, p, r) {
return p in t ? Reflect.get(t, p, r) : fallback;
}
});
}
const scores = withDefault({ ada: 90 }, 0);
console.log(scores.ada);
console.log(scores.unknown);数组负索引
通过在 get 拦截器中转换索引,让数组支持类似 Python 的负索引。
function negIndex(arr) {
return new Proxy(arr, {
get(t, p, r) {
const i = Number(p);
if (Number.isInteger(i) && i < 0) {
return Reflect.get(t, t.length + i, r);
}
return Reflect.get(t, p, r);
}
});
}
const list = negIndex(['a', 'b', 'c']);
console.log(list[-1]);
console.log(list[0]);只读视图
提供一个可以读取但永远不能写入的对象,可用于保护共享的 config。
function readonly(obj) {
return new Proxy(obj, {
set() { console.log('blocked write'); return false; },
deleteProperty() { console.log('blocked delete'); return false; }
});
}
const config = readonly({ apiUrl: '/api' });
config.apiUrl = '/hacked';
console.log(config.apiUrl);统计访问次数
将 counts 存储在 target 外部,以跟踪每个属性被读取的次数。
function counted(obj) {
const counts = {};
const proxy = new Proxy(obj, {
get(t, p, r) {
counts[p] = (counts[p] || 0) + 1;
return Reflect.get(t, p, r);
}
});
return { proxy, counts };
}
const { proxy, counts } = counted({ x: 1 });
proxy.x; proxy.x; proxy.x;
console.log(counts.x);计算虚拟属性
公开未被存储的派生值,并在每次读取时重新计算。
const rect = new Proxy({ width: 4, height: 3 }, {
get(t, p, r) {
if (p === 'area') return t.width * t.height;
return Reflect.get(t, p, r);
}
});
console.log(rect.area);
rect.width = 10;
console.log(rect.area);读取未知属性时抛出异常
当代码读取不存在的属性时抛出异常,从而尽早发现拼写错误。
function strict(obj) {
return new Proxy(obj, {
get(t, p, r) {
if (typeof p === 'string' && !(p in t)) {
throw new ReferenceError('unknown property: ' + p);
}
return Reflect.get(t, p, r);
}
});
}
const o = strict({ name: 'Ada' });
console.log(o.name);
try { console.log(o.naem); } catch (e) { console.log(e.message); }组合多个关注点
实际的包装器通常会在一个处理程序中结合验证和日志记录,并让每个拦截器都通过 Reflect 转发操作。
const account = new Proxy({ balance: 0 }, {
set(t, p, v, r) {
if (p === 'balance' && v < 0) throw new RangeError('no overdraft');
console.log(p + ' set to ' + v);
return Reflect.set(t, p, v, r);
}
});
account.balance = 100;
console.log(account.balance);
try { account.balance = -50; } catch (e) { console.log(e.message); }这些模式为何重要
代理对象可以添加横切行为、验证、日志记录、默认值和访问控制,而不会污染原始对象或其调用方。这正是响应式框架观察 state 变化的方式。当您需要透明地拦截操作时,可以使用它们。
const observed = new Proxy({ n: 0 }, {
set(t, p, v, r) {
const ok = Reflect.set(t, p, v, r);
console.log(p + ' is now ' + t[p]);
return ok;
}
});
observed.n = 1;
observed.n = 2;快速检查
如果要在无效值被存储之前拒绝它们,应使用哪个代理拦截器?
回顾:代理对象的实际使用场景
您将代理对象应用到了实际问题中:
- set 拦截器中的验证会拒绝错误数据。
- 日志记录通过
Reflect跟踪读取和写入。 - 默认值和虚拟属性位于 get 拦截器中。
- 只读视图、访问计数和严格的拼写错误检查都可以透明地包装对象。
常见问题解答
「Proxy 的实际应用场景」课时是免费的吗?
是的 — 「Proxy 的实际应用场景」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 JavaScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 JavaScript Academy 课程共包含 4 节课。
「Proxy 的实际应用场景」这节课中我会学到什么?
构建验证、日志记录和响应式对象。 你通过在浏览器中直接运行的动手代码来练习 JavaScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 JavaScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 JavaScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「Proxy 的实际应用场景」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 JavaScript Academy 课中编写并运行代码吗?
能。每节 JavaScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 创建 Proxy
- get 和 set 陷阱
- Reflect API
- Proxy 的实际应用场景