JavaScript进阶21笔记
从 ECMAScript 2015 开始,JavaScript 获得了
代理
在 ECMAScript 6 中引入的
let handler = {
get: function(target, name){
return name in target ? target[name] : 42;
}};
let p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 1, 42
Proxy
对象定义了一个目标(这里是一个空对象)和一个实现了 get
陷阱的 handler 对象。这里,代理的对象在获取未定义的属性时不会返回 undefined
,而是返回 42。
术语
包含陷阱的占位符对象。
-
traps
提供属性访问的方法。这类似于操作系统中陷阱的概念。
-
target
代理虚拟化的对象。它通常用作代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。
-
invariants
实现自定义操作时保持不变的语义称为不变量。如果你违反处理程序的不变量,则会抛出一个
句柄和陷阱
以下表格中总结了 Proxy
对象可用的陷阱。
Handler / trap | Interceptions | Invariants |
---|---|---|
getPrototypeOf 方法一定返回一个对象或null .如果 target 不可扩展,Object.getPrototypeOf(proxy) 必须返回和 Object.getPrototypeOf(target) 一样的值。 |
||
如果 target 不可扩展,prototype 参数必须与Object.getPrototypeOf(target) 的值相同。 |
||
Object.isExtensible(proxy) 必须返回和Object.isExtensible(target) 一样的值。 |
||
如果Object.isExtensible(proxy) 值为 false,Object.preventExtensions(proxy) 只返回true。 |
||
getOwnPropertyDescripton 只能返回对象或者undefined .A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible.A property cannot be reported as existent, if it does not exists as an own property of the target object and the target object is not extensible.A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.The result of Object.getOwnPropertyDescriptor(target) can be applied to the target object using Object.defineProperty and will not throw an exception. |
||
A property cannot be added, if the target object is not extensible.A property cannot be added as or modified to be non-configurable, if it does not exists as a non-configurable own property of the target object.A property may not be non-configurable, if a corresponding configurable property of the target object exists.If a property has a corresponding target object property then Object.defineProperty(target, prop, descriptor) will not throw an exception.In strict mode, a false return value from the defineProperty handler will throw a |
||
Property query: foo in proxy Inherited property query: foo in Object.create(proxy) |
A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible. | |
Property access: proxy[foo] and proxy.bar Inherited property access: Object.create(proxy)[foo] |
The value reported for a property must be the same as the value of the corresponding target object property if the target object property is a non-writable, non-configurable data property.The value reported for a property must be undefined if the corresponding target object property is non-configurable accessor property that has undefined as its [[Get]] attribute. | |
Property assignment: proxy[foo] = bar and proxy.foo = bar Inherited property assignment: Object.create(proxy)[foo] = bar |
Cannot change the value of a property to be different from the value of the corresponding target object property if the corresponding target object property is a non-writable, non-configurable data property.Cannot set the value of a property if the corresponding target object property is a non-configurable accessor property that has undefined as its [[Set]] attribute.In strict mode, a false return value from the set handler will throw a |
|
Property deletion: delete proxy[foo] and delete proxy.foo |
A property cannot be deleted, if it exists as a non-configurable own property of the target object. | |
handler.enumerate() |
Property enumeration / for...in: for (var name in proxy) {...} Reflect.enumerate() |
The enumerate method must return an object. |
The result of ownKeys is a List.The Type of each result List element is either |
||
proxy(..args) |
There are no invariants for the handler.apply method. |
|
new proxy(...args) |
结果一定是一个Object 。 |
撤销Proxy
var revocable = Proxy.revocable({}, {
get: function(target, name) {
return "[[" + name + "]]";
}
});
var proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // TypeError is thrown
proxy.foo = 1 // TypeError again
delete proxy.foo; // still TypeError
typeof proxy // "object", typeof doesn't trigger any trap
反射
Reflect
有助于将默认操作从处理程序转发到目标。
以
Reflect.has(Object, "assign"); // true
更好的apply
函数
在 ES5 中,我们通常使用
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
使用
Reflect.apply(Math.floor, undefined, [1.75]);
// 1;
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
// "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index;
// 4
Reflect.apply(''.charAt, 'ponies', [3]);
// "i"
检查属性定义是否成功
使用
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构