使用JavaScript ES6 Proxies时,直接分配数组索引时不会触发array.length的set属性陷阱.
例如:
const proxy = new Proxy([], {
set: function(obj, name, value) {
console.log(`set: ${name}`);
obj[name] = value;
return true;
}
});
proxy.push(0);
proxy[1] = 1;
Run Code Online (Sandbox Code Playgroud)
Chrome 51和Firefox 47输出:
set: 0 set: length set: 1
虽然我期望:
set: 0 set: length set: 1 set: length
这是按规格吗?我找不到任何关于此的信息.
我有一个从构造函数返回Proxy的类。当我尝试将此类的实例存储在IndexedDB中或使用发送对象时window.postMessage(),收到一条错误消息,指出无法克隆该对象。看来结构化克隆算法无法处理代理对象。
以下代码演示了该错误:
class MyClass {
constructor() {
return new Proxy(this, {
set(target, prop, val, receiver) {
console.log(`"${prop}" was set to "${val}"`);
return Reflect.set(target, prop, val, receiver);
}
});
}
}
const obj = new MyClass;
try {
window.postMessage(obj,'*');
} catch(err) {
console.error(err);
}Run Code Online (Sandbox Code Playgroud)
谁能建议解决此问题的方法?我看到了两个潜在的解决方案,但是我不知道如何实现它们:
不要从构造函数返回Proxy,而是以某种方式在类声明中维护Proxy功能。
更改代理实例,使其与结构化克隆算法一起使用。
编辑:以下更简单的代码也演示了结构化克隆错误:
const p = new Proxy({}, {});
window.postMessage(p, '*');Run Code Online (Sandbox Code Playgroud)
假设我有一个像这样的代理实例:
const getProxy = function(){
return new Proxy({}, ...);
}
const proxy = getProxy();
Run Code Online (Sandbox Code Playgroud)
稍后,我想从代理中检索目标,有没有办法做到这一点?就像是:
const target = proxy.getOriginalTarget()
Run Code Online (Sandbox Code Playgroud) 我正在使用 ES6 代理。我已经创建了一个数组的代理,现在当我检查代理的类型时,它给我作为Object类型。
问题:
如何检查我创建的代理是用于数组还是对象?
例子:
const arr = ['a', 'b', 'c'];
const arrProxy = new Proxy(arr, {});
alert(typeof(arrProxy));Run Code Online (Sandbox Code Playgroud)
更新(解决方案):typeof我们应该使用
而不是使用Array.isArray
const arr = ['a', 'b', 'c'];
const arrProxy = new Proxy(arr, {});
alert(Array.isArray(arrProxy));
Run Code Online (Sandbox Code Playgroud) 如何为浏览器原生 DOM 对象创建代理?
我想拦截元素样式的设置。所以我为 DOM 对象创建一个代理。但是,当我使用某些函数(例如getComputedStyle().
const setHandler = (target: any, prop: PropertyKey, value: any, _receiver?: any) => {
if (/*some condition*/) {
target[prop] = value
}
return true
}
const getHandler = (target: any, prop: PropertyKey, _receiver?: any) => {
return target[prop]
}
const style = new Proxy(el.style, {
get: getHandler,
set: setHandler
})
const classList = new Proxy(el.classList,{
get: getHandler,
set: setHandler
})
const proxy = new Proxy(el/*HTMLElement*/, {
get: (target, prop, _receiver) => …Run Code Online (Sandbox Code Playgroud) 为什么要撤销代理?您能提供一个实际应用吗Proxy.revocable()?
根据MDN Proxy.revocable() 文档,我了解它允许垃圾收集。但是,如果你刚刚删除了 Proxy 对象,不是也允许垃圾回收吗?
附录:如果这个问题有问题,请告诉我它是什么,我很乐意改写或添加其他信息。
@艾米:
我认为这似乎是一个不必要的内置功能,因为我可以像这样创建一个可撤销代理:
function createRevocable(o,handlers){
var revoked = false
var handlerWrapper = {
get(...args){
if(revoked){
throw Error('Sorry, this object went poof.')
}
if(typeof handlers.get == 'function'){
return handlers.get(...args)
}else{
return Reflect.get(...args)
}
}
}
var p = new Proxy(o,Object.assign({},handlers,handlerWrapper))
var r = function(){
revoked = true
}
return {r,p}
}
var a = createRevocable({a:1},{})
var prox = a.p
var revoke = a.r
console.log(prox.a) //1
revoke()
console.log(prox.a)Run Code Online (Sandbox Code Playgroud)
然而,垃圾收集似乎确实是问题所在,因为我可以撤销对该对象的访问,但无法删除 Proxy 对象内对其的内部引用。除非...
function …Run Code Online (Sandbox Code Playgroud)请参阅 Mozilla 文档中有关Proxy()的内容
一个简单的代理示例:
const handler = {
get: function(target, prop, receiver) {
return Reflect.get(target, prop, receiver);
},
set: function(target, prop, receiver) {
return Reflect.set(target, prop, receiver);
}
};
const proxy = new Proxy(target, handler);
Run Code Online (Sandbox Code Playgroud)
get我在and中有一些异步函数set,所以我想让get和setto 成为async函数。
我期望类似的东西:
const handler = {
get: async function(target, prop, receiver) {
await foo();
return Reflect.get(target, prop, receiver);
},
set: async function(target, prop, receiver) {
await bar();
return Reflect.set(target, prop, receiver);
}
};
const …Run Code Online (Sandbox Code Playgroud) 我有一些从网络服务器获取的对象。对象的某些属性需要额外的异步解析,但出于性能原因我想延迟执行此操作。我试图使用代理来拦截访问,然后在访问时解析属性。我的处理程序看起来像这样
class MyClass {
type() {
return "my new class";
}
}
let myObject = new MyClass();
let proxy = new Proxy(myObject, {
get: async(target, prop, receiver) => {
if (prop === "attribute") {
let newProp = prop + "_parsed";
if (!(newProp in target)) {
return await (new Promise((resolve, reject) => { resolve("parsed value") }));
}
else {
return target[newProp];
}
}
else {
return Reflect.get(target, prop, receiver);
}
},
});
console.log(proxy.attribute); // "parsed value"
console.log(proxy.type()); // "my new class" …Run Code Online (Sandbox Code Playgroud)我无法弄清楚为什么以下代码不起作用:
var os = new Proxy(require('os'), {});
console.log( os.cpus() ); // TypeError: Illegal invocation
Run Code Online (Sandbox Code Playgroud)
然而
var os = require('os');
console.log(Reflect.apply(os.cpus, os, []));
Run Code Online (Sandbox Code Playgroud)
或者
var os = new Proxy(require('os'), {});
console.log( os.platform() );
Run Code Online (Sandbox Code Playgroud)
按预期工作。
我最近了解了ES6代理,但我没有看到使用它的充分理由.我的意思是,除非我遗漏了什么,否则可以在没有它的情况下完成所有可以使用Proxy的事情.
例如,大多数人谈论代理时的验证,但可以应用一些JS优点来验证,每个人都很好.如果有人可以睁开眼睛看看代理的一些主要用例,我将不胜感激.谢谢!
es6-proxy ×10
javascript ×9
ecmascript-6 ×3
node.js ×2
proxy ×2
async-await ×1
asynchronous ×1
dom ×1
handler ×1