JS代理HTML5画布上下文

4
我希望代理绘画API以便测试抽象方法是否确实绘制到画布上,但是在代理后,我遇到了错误: 'strokeStyle' setter called on an object that does not implement interface CanvasRenderingContext2D
这段代码被简化了,但会抛出同样的错误:

/** !NB: This snippet will probably only run in Firefox */
var canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
canvas.style.backgroundColor = '#FF0000';

var ctx = canvas.getContext("2d");                          
var calls = [];

var handler = {
    get( target, property, receiver ) {

        if ( typeof ctx[property] === 'function' ){
            return function( ...args ){
                calls.push( { call: property, args: args } )
                return ctx[property]( ...args );
            };
        }

        return ctx[property];
    }
};

try {
    document.body.appendChild(canvas);
    var proxy = new Proxy( ctx, handler );
    
    proxy.scale( 1, 1 );
    proxy.strokeStyle = '#000000';
    
    canvas.getContext = function(){
        return proxy;  
    };
}
catch( e ) {
    document.getElementById('message').innerHTML = 'Error: ' + e.message;   
}
<div id="message"></div>

有什么想法吗?
1个回答

6
您可以通过在处理程序上定义一个set方法来解决此错误:
set(target, property, value, receiver) {
    target[property] = value;
}

这个错误的原因可能有点奇怪。 CanvasRenderingContext2D 实例没有自己的 strokeStyle 属性。相反,每个 CanvasRenderingContext2D 实例的原型 CanvasRenderingContext2DPrototype 有一个访问器属性,其 set/get 组件将为实例设置和获取描边样式值。
> ctx.hasOwnProperty("strokeStyle")
false

> Object.getOwnPropertyDescriptor(ctx.__proto__, "strokeStyle")
Object { get: strokeStyle(), set: strokeStyle(), enumerable: true, configurable: true }

(如果您对此模式感兴趣,请查看我在JSON.parse not erroring on cyclic objects上的答案。)
问题在于提供给CanvasRenderingContext2DPrototype.strokeStyle setter的“this”是代理对象,而不是实际的ctx对象。也就是说,当我们仅在代理上设置属性时:
proxy.isAFake = true;

并在重新定义的 setter 中进行测试:

Object.defineProperty(ctx.__proto__, "strokeStyle", {
    set: function() {
        console.log("strokeStyle setter called for proxy?", this.isAFake);
    }
});

我们可以看到setter记录了代理属性:strokeStyle setter called for proxy? true
由于某些原因,CanvasRenderingContext2DPrototype.strokeStyle的setter只接受真正的CanvasRenderingContext2D实例,而不是代理实例。

作为一个附加说明,即使添加了setter,我仍然遇到麻烦,因为我的代码中有一个错误,我在其中设置了ctx.strokeStyle = colour,其中colour是未定义的。我看到的错误没有提供帮助,它指向了代理对象: TypeError: proxy set handler returned false for property '"strokeStyle"' - thelastshadow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接