[英]JavaScript prototype inheritance and html canvas
我是一名 Ruby 开发人员,最终决定认真学习 JavaScript。 所以我买了一些书并开始深入研究,但是当我试图理解原型继承时,我很快就卡住了……
本书的例子之一如下。 给定一个 Shape,其原型具有一个 draw 方法,以及两个子形状:一个 Triangle 和一个 Rectangle,其原型继承自 Shape;
一切都是可以理解的,直到我添加了第三种方法来填充形状......而且只有最后一种被填充。 不管我叫哪一个。 为什么? 画布有什么特别之处吗?
下面是练习的代码:
function Point(x, y) { this.x = x; this.y = y; } function Shape() { this.points = []; this.init(); } Shape.prototype = { constructor: Shape, init: function() { if (this.context === undefined) { Shape.prototype.context = document.getElementById('canvas').getContext('2d'); }; if (this.name === undefined) { Shape.prototype.name = 'generic shape' } }, draw: function() { var i, ctx = this.context; ctx.strokeStyle = 'rgb(0,0,255)'; ctx.beginPath(); ctx.moveTo(this.points[0].x, this.points[0].y); for (i = 1; i < this.points.length; i++) { ctx.lineTo(this.points[i].x, this.points[i].y); } ctx.closePath(); ctx.stroke(); }, fill: function(color) { var ctx = this.context; ctx.fillStyle = color; ctx.fill(); }, say_name: function() { console.log('Hello my name is ' + this.name) } }; function Triangle(a, b, c) { this.points = [a, b, c]; this.name = 'Triangle' this.context = document.getElementById('canvas').getContext('2d'); } function Rectangle(side_a, side_b) { var p = new Point(200, 200); this.points = [ p, new Point(px + side_a, py), // top right new Point(px + side_a, py + side_b), // bottom right new Point(px, py + side_b) // bottom left ]; this.name = 'Rectangle' this.context = document.getElementById('canvas').getContext('2d'); } (function() { var s = new Shape(); Triangle.prototype = s; Rectangle.prototype = s; })(); function testTriangle() { var p1 = new Point(100, 100); var p2 = new Point(300, 100); var p3 = new Point(200, 0); return new Triangle(p1, p2, p3); } function testRectangle() { return new Rectangle(100, 100); } function make_me_crazy() { var t = testTriangle(); var r = testRectangle(); t.draw(); r.draw(); t.say_name(); r.say_name(); t.fill('red'); } make_me_crazy();
<canvas height='600' width='800' id='canvas' />
谢谢!
更多细节:
say_name
完全正常工作我期望说:“我是三角形”或“我是矩形”而不是“我是通用形状”,但fill
函数填充了矩形,尽管我在三角形上调用它实例? 当人们正确回答翻转两个绘制函数调用时,我会更好地指定以下内容。 问题不在于形状的颜色,而在于上下文指针。 为什么只填充最后一个形状? 如果我在调用fill
之前添加更多形状,则只会fill
最后一个。 这意味着我在提到画布时做错了。 我以为它是“我绘制形状的地方”,但它似乎更像是“最后一个活动形状”问题的核心是上下文 - 您的形状共享画布的单个上下文,因此在对象之间来回翻转并不简单。 相反,将您的操作顺序视为一次处理一个形状,只有在完成前一个形状后才移动到下一个形状。
注意make_me_crazy
函数中的调用顺序:
function Point(x, y) { this.x = x; this.y = y; } function Shape() { this.points = []; this.init(); } Shape.prototype = { constructor: Shape, init: function(){ if (this.context === undefined) { Shape.prototype.context = document.getElementById('canvas').getContext('2d'); }; if(this.name === undefined){ Shape.prototype.name = 'generic shape' } }, draw: function(){ var i, ctx = this.context; ctx.strokeStyle = 'rgb(0,0,255)'; ctx.beginPath(); ctx.moveTo(this.points[0].x, this.points[0].y); for (i = 1; i<this.points.length; i++) { ctx.lineTo(this.points[i].x, this.points[i].y); } ctx.closePath(); ctx.stroke(); }, fill: function(color){ var ctx = this.context; ctx.fillStyle = color; ctx.fill(); }, say_name: function(){console.log('Hello my name is '+ this.name)} }; function Triangle(a,b,c){ this.points = [a, b, c]; this.name = 'Triangle' this.context = document.getElementById('canvas').getContext('2d'); } function Rectangle(side_a, side_b){ var p = new Point(200, 200); this.points = [ p, new Point(px + side_a, py),// top right new Point(px + side_a, py + side_b), // bottom right new Point(px, py + side_b)// bottom left ]; this.name = 'Rectangle' this.context = document.getElementById('canvas').getContext('2d'); } (function(){ var s = new Shape(); Triangle.prototype = s; Rectangle.prototype = s; })(); function testTriangle(){ var p1 = new Point(100, 100); var p2 = new Point(300, 100); var p3 = new Point(200, 0); return new Triangle(p1, p2, p3); } function testRectangle(){ return new Rectangle(100, 100); } function make_me_crazy(){ var t = testTriangle(); t.say_name(); t.draw(); t.fill('red'); var r = testRectangle(); r.draw(); r.say_name(); } make_me_crazy();
<canvas height='600' width='800' id='canvas'></canvas>
关于你问题的要点。
对于第一个:关键是这行代码
if(this.name === undefined){
Shape.prototype.name = 'generic shape'
}
当您实例化Rectangle
和Triangle
,它们都会设置name
。 另一方面, render
方法仅在Shape
原型中可用。
关于第二点(和第三点):也许你在Triangle
绘制Rectangle
。 尝试切换draw
调用的顺序来检查它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.