如何扩展 CanvasRenderingContext2D (如果可能的话,在 ES6 风格的脚本中)

Cap*_*ara 5 javascript canvas ecmascript-6

我想创建一个扩展的新类CanvasRenderingContext2D。这样我就可以将用户定义的属性分配给prototype该新类的属性,而不是分配给CanvasRenderingContext2D.attribute. 以下是我打算写的代码:

class WL_CRC2D extends CanvasRenderingContext2D{
    constructor(){
        super();
    }
    setStyle(args){//...
    }
    //...
}

var ctx = new WL_CRC2D() // Uncaught TypeError: Illegal constructor
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为CanvasRenderingContext2D会阻止new操作符 - 正如以下代码也会引发错误:

var ctx = new CanvasRenderingContext2D(); // Uncaught TypeError: Illegal constructor
Run Code Online (Sandbox Code Playgroud)

然后我尝试用另一种方式重写构造函数:

 class WL_CRC2D{
    constructor(){
        let ctxTemp = Object.create(CanvasRenderingContext2D.prototype);
        for (let i of Reflect.ownKeys(ctxTemp.__proto__)){
            Object.defineProperty(this.__proto__, i, Object.getOwnPropertyDescriptor(ctxTemp.__proto__, i));
        }
    }
    setStyle(args){//...
    }
    //...
}

var ctx = new WL_CRC2D(); // fine
console.log(ctx.arc); // function arc() { [native code] }
ctx.arc(0, 0, 10, 0, 1, true); // Uncaught TypeError: Illegal invocation
Run Code Online (Sandbox Code Playgroud)

正如注释所示,以WL_CRC2D这种方式创建的新实例实际上无法访问WL_CRC2D.prototype.

那么有没有一种方法可以避免污染系统定义的类CanvasRenderingContext2D呢?请指教。谢谢!

Cap*_*ara 0

我可能以一种丑陋的方式解决了这个问题:

class WL_CanvasRenderingContext2D{
    constructor(ctx){
        this.ctx = ctx;
    }
}
(() => {
    var context = document.createElement('canvas').getContext('2d');
    for (let i of Reflect.ownKeys(Object.getPrototypeOf(ctx))){
        if (['symbol', 'constructor'].indexOf(typeof i) < 0){
            var propertyDesc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(context), i);
            if (typeof context[i] != 'function'){
                [propertyDesc.get, propertyDesc.set] = [function(){return this.ctx[i]}, function(val){this.ctx[i] = val;}];
            }
            else{
                propertyDesc.value = function(...args) {this.ctx[i].apply(this.ctx, args)};
            }
            Object.defineProperty(WL_CanvasRenderingContext2D.prototype, i, propertyDesc);
        }
    }
})();

var a = new WL_CanvasRenderingContext2D(ctx);
Run Code Online (Sandbox Code Playgroud)

如果上面的代码有任何缺陷,请仍然通知我。谢谢!