2017-02-10 2 views
1

Я разработчик Ruby, который, наконец, решил серьезно изучить JavaScript. Поэтому я купил несколько книг, и я начал погружаться, но я быстро застрял, когда попытался понять прототипное наследование ...Наследование прототипа JavaScript и html canvas

Одним из примеров книги является следующее. Учитывая форму, у которой прототип имеет метод рисования, и две дочерние фигуры: треугольник и прямоугольник, который прототип наследует от Shape;

  • Когда я вызываю функцию 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(p.x + side_a, p.y), // top right 
 
    new Point(p.x + side_a, p.y + side_b), // bottom right 
 
    new Point(p.x, p.y + 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 функция заполняет прямоугольник, несмотря на то, что я вызываю его на экземпляр треугольника? Поскольку люди правильно ответили, чтобы перевернуть два вызова функции draw, я бы уточнил следующее. Проблема не в цвете формы, а в контексте указатель. почему заполняется только последняя форма? Если я добавлю больше фигур, прежде чем звонить fill, только последние заполняются. Это означает, что я делаю что-то неправильно, ссылаясь на холст. Я предположил, что это «место, где я рисую фигуры», но это похоже на «последнюю активную форму»
  • Как я могу исправить этот код, чтобы он правильно работал, заполняя форму, которую я хочу всякий раз, когда я хочу? Я имею в виду. что, если я хочу иметь функцию, которая получает экземпляр определенной формы и заполняет ее?
  • Есть ли способ доступа к ничьи, содержащиеся в холсте?
+0

В вашей 'make_me_crazy' функции, переключать отрисовки вызовов (нарисовать прямоугольник первой, а затем треугольник). Результат этого должен рассказать вам что-то о контексте! – chazsolo

+0

Да, вы правы. Я предполагал, что контекст будет «формой, над которой я работаю», но не ... это ... холст? Если я добавляю третью фигуру, метод заполнения заполняет ее. Поэтому я вывод контекста - это последняя активная форма, независимо от того, какой метод называет метод fill ... но почему? Как правильно обращаться к форме в любой момент? –

ответ

0

Сведения о точках вашего вопроса.

Для первого: ключ эта строка кода

if(this.name === undefined){ 
    Shape.prototype.name = 'generic shape' 
} 

При создании экземпляра Rectangle и Triangle, оба из них установлен name. С другой стороны, метод render доступен только в прототипе Shape.

О втором пункте (и третьем): Возможно, вы рисуете Rectangle над Triangle. Попробуйте переключить порядок звонков draw, чтобы проверить его.

+0

Render метод? mmhh, возможно, это и есть смысл, поскольку я использую тот же холст для всех фигур, может быть, мне нужно «сбросить» контекст в форму, которую я хочу заполнить ... но как? –

+0

И нет, две формы не перекрываются. (и если я добавлю другие формы, метод заполнения всегда заполняет последний). –

1

Ядро проблемы - это контекст - ваши формы разделяют контекст холста, и поэтому он не является прямым движением вперед и назад между объектами. Вместо этого подумайте о том, как ваш порядок действий обрабатывается одной фигурой за раз и только переходит к следующему, когда вы закончите с первым.

Обратите внимание на порядок вызовов в функции 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(p.x + side_a, p.y),// top right 
 
     new Point(p.x + side_a, p.y + side_b), // bottom right 
 
     new Point(p.x, p.y + 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>

+0

Правильно. Я заставил меня переосмыслить свои вопросы, чтобы найти лучший способ выразить свои сомнения. Спасибо! –

+0

Это правильный ответ, я удаляю мой. –

Смежные вопросы