我想在Javascript中定义我的自定义Canvas2D类,它来自原生的html5 canvas对象。我尝试用原型继承而不是经典方式来做这件事:
function Canvas2D(){
var parent = document.createElement("canvas");
var child = Object.create(parent);
child.getContext = function(){
return parent.getContext('2d');
};
return child;
}
所以我可以用这种方式创建和使用对象实例
var canvas = new Canvas2D();
var context = canvas.getContext();
但是,当我尝试获取html5原生的width
属性时:
var width = canvas.width;
我的浏览器抛出Uncaught TypeError: Illegal invocation
异常。难道这个属性也不应该继承吗?我想这个问题与一些" get或set"限制或是某种访问修饰符对html5本机画布对象中属性的限制。
当我尝试使用自定义画布的实例作为参数调用drawImage
时:
canvas.getContext().drawImage(new Canvas2D(), 300, 150);
浏览器抛出另一个异常 - Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
换句话说,浏览器抱怨我传递给drawImage方法的Canvas2D对象的类型,虽然我的画布是HTMLCanvasElement类型!我们可以使用以下行轻松查看:
console.log(new Canvas2D() instanceof HTMLCanvasElement);
在我的浏览器中打印出true
。
所以我的问题是:
1)有人可以解释“宽度”错误行为背后的原因吗?财产,我该如何解决?
2)我怎样才能强制drawImage将我的类识别为HTMLCanvasElement?
答案 0 :(得分:2)
你可能不会。值得一提的是,HTMLCanvasElement
(以及其他HTMLXY-s)也是一个接口,这意味着实际实现可能包含的细节根本不会出现在JavaScript级别上。就像画布一样,肯定有一个后备缓冲区,你根本看不到它。因此,制作副本的预期成功至少是值得怀疑的。
尝试一对简单的
console.log(document.createElement("canvas").width);
console.log(Object.create(document.createElement("canvas")).width);

已经表明它无法创建真正的HTMLCanvasElement
。事实上,Object.create()
甚至没有那么努力:
- 如果Type(O)不是Object或Null则抛出TypeError异常。
- 让obj成为创建新对象的结果,就好像通过表达式new Object(),其中Object是具有该名称的标准内置构造函数
- 将obj的[[Prototype]]内部属性设置为O。
- 如果参数Properties存在且未定义,则将自己的属性添加到obj,就好像通过调用带有参数obj和Properties的标准内置函数Object.defineProperties一样。
- 返回obj。
醇>
new Object()
尝试更加困难,它指定 主机对象 (HTMLXY-s)也被考虑在内:
1.a.i如果值是本机ECMAScript对象,请不要创建新对象,只需返回值。
1.a.ii如果值是主机对象,则执行操作并以依赖于实现的方式返回结果,该方式可能取决于主机对象。
使用new Object
测试您的代码:
function Canvas2D(){
var parent = document.createElement("canvas");
var child = new Object(parent);
child.getContext = function(){
return parent.getContext('2d');
};
console.log(parent===child);
return child;
}
var cnv=new Canvas2D();
console.log(cnv.width);
var ctx=cnv.getContext();

它得到了正确的width
(默认为300),但有一些可疑的东西" copy" (请参阅检查child===parent
,结果为true,暗示没有创建新对象,并且getContext
的无限递归 - 至少在Chrome中 - 建议相同)。这里和现在我不知道它是1.ai(不应该是这种情况,画布或HTMLCanvasElement不是ECMA / JavaScript的一部分),或1.a.ii(遇到主机对象时依赖于实现的行为) ),但它无法确定。并且不期望:开头提到的,JavaScript级别的复制构造函数"无法了解实际实现对象的浏览器级细节。