如何解决为什么当我代理它时,这个 setter 没有给我截获的值?
我确定我创建代理的方式是正确的,因为当我将属性登录到 devtools 控制台时,我可以看到设置器已被代理。
我主要是按照这个 Question 的回答来构建这个的。尽管如此,我必须说这个答案看起来很复杂,所以我从中剥离了很多东西,以采用简单的风格,您可以从下面的代码中看到。
class Hook {
constructor(object) {
if (object) {
this.object = object;
}
}
add(object) {
this.object = object;
}
proxy(handler) {
return new Proxy(this.object,handler);
}
};
const hook = new Hook();
Object.getownPropertyNames(CanvasRenderingContext2D.prototype).forEach(function (property) {
let propertyDescription = Object.getownPropertyDescriptor(CanvasRenderingContext2D.prototype,property);
const proxyPropertyDescription = {
configurable: propertyDescription.configurable,enumerable: propertyDescription.enumerable
}
if (typeof propertyDescription.value === "function") {
const handle = {
apply(target,thisArg,args) {
// forward invocation to underlying function
console.log("apply",target,args)
return target.apply(thisArg,args)
}
};
hook.add(propertyDescription.value)
proxyPropertyDescription.writable = propertyDescription.writable;
proxyPropertyDescription.value = hook.proxy(handle,true);
}
if (propertyDescription.set) {
const handle = {
set(target,key,value) {
// forward access to underlying property
Reflect.set(target,value);
console.log("set",value);
}
};
hook.add(propertyDescription.set)
proxyPropertyDescription.set = hook.proxy(handle,true);
}
Object.defineProperty(CanvasRenderingContext2D.prototype,property,proxyPropertyDescription);
})
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
// My target but it never get proxified
ctx.font = "14px 'Arial'";
// But functions like this works....
ctx.fill("red");
// I can see that on Devtools when I log this Property has been set to Proxy
console.log(Object.getownPropertyDescriptor(CanvasRenderingContext2D.prototype,"font"));
解决方法
不要将 getter/setter 与代理混用。使用其中之一,不要同时使用。
这是一个仅使用属性描述符的解决方案:
const hook = {
wrapMethod(name,method) {
return function(...args) {
console.log("applying method "+name,args);
return method.apply(this,args);
};
},wrapSetter(name,setter) {
return function(value) {
console.log("setting "+name,value);
return setter.call(this,value);
};
}
};
const proto = CanvasRenderingContext2D.prototype;
for (const name of Object.getOwnPropertyNames(proto)) {
const descriptor = Object.getOwnPropertyDescriptor(proto,name);
if (!descriptor.configurable) {
console.log("Cannot hook onto immutable ."+name);
continue;
} else if (typeof descriptor.value == "function") {
descriptor.value = hook.wrapMethod(name,descriptor.value);
} else if (descriptor.set) {
descriptor.set = hook.wrapSetter(name,descriptor.set);
} else {
console.log("Did not hook onto ."+name,descriptor);
}
Object.defineProperty(proto,name,descriptor);
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "14px 'Arial'";
ctx.fillStyle = "red";
ctx.fillRect(130,190,40,60);
这是一个仅使用代理的解决方案:
const hook = {
wrapMethod(name,value);
};
}
};
const contextProto = CanvasRenderingContext2D.prototype;
const canvasProto = HTMLCanvasElement.prototype;
const getContext = canvasProto.getContext;
canvasProto.getContext = function(...args) {
const ctx = getContext.apply(this,args);
if (ctx && Object.getPrototypeOf(ctx) == contextProto)
Object.setPrototypeOf(ctx,proxy);
return ctx;
};
const proxy = new Proxy(contextProto,{
get(target,receiver) {
const value = Reflect.get(target,receiver);
return typeof value == "function" ? hook.wrapMethod(name,value) : value;
},set(target,value,receiver) {
hook.wrapSetter(name,function(value) {
Reflect.set(target,this);
}).call(receiver,value);
},});
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "14px 'Arial'";
ctx.fillStyle = "red";
ctx.fillRect(130,60);
这是相当低效的,因为方法和设置器在每次访问时都被包装,而不仅仅是一次。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。