簡體   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