繁体   English   中英

JavaScript 原型继承和 html 画布

[英]JavaScript prototype inheritance and html canvas

我是一名 Ruby 开发人员,最终决定认真学习 JavaScript。 所以我买了一些书并开始深入研究,但是当我试图理解原型继承时,我很快就卡住了……

本书的例子之一如下。 给定一个 Shape,其原型具有一个 draw 方法,以及两个子形状:一个 Triangle 和一个 Rectangle,其原型继承自 Shape;

  • 当我在 Triangle 和 Rectangle 实例上调用 draw 函数时,该方法将正确绘制它们。
  • 当我添加第二个方法来显示他们的名字时,每个实例都会正确记录它。

一切都是可以理解的,直到我添加了第三种方法来填充形状......而且只有最后一种被填充。 不管我叫哪一个。 为什么? 画布有什么特别之处吗?

下面是练习的代码:

 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'
}

当您实例化RectangleTriangle ,它们都会设置name 另一方面, render方法仅在Shape原型中可用。

关于第二点(和第三点):也许你在Triangle绘制Rectangle 尝试切换draw调用的顺序来检查它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM