Прототипное ООП в JS базируется на простой идее, которую следует запомнить: каждый объект имеет прототип, т. е. другой объект, в котором ищуться поля в случае отсутствия их в оригинальном объекте:
var a = {};
a.toString() // "[object Object]"
a.__proto__ // Object {}
a.__proto__.constructor // function Object() { [native code] }
a.toString()
отсутствует как явно определенный в объекте a
, однако он найден в прототипе Object
.
function Drawable(){
Drawable.prototype.addInstance(this);
}
Drawable.prototype.draw = function(){};
Drawable.prototype.instances = [];
Drawable.prototype.addInstance = function(item){
Drawable.prototype.instances.push(item);
}
Drawable.prototype.drawAll = function(){
for(var i = 0; i<Drawable.prototype.instances.length;i++){
Drawable.prototype.instances[i].draw();
}
}
Определенные в прототипе поля являются статическими (общими) для класса, так как у всех объектов класса есть один объект-прототип. При этом они
работают как методы каждого объекта, если используют this
, являющийся ссылкой на конкретный объект.
Наследование в JS обычно реализуется в два этапа - создание одного объекта с прототипом предка, насыщение его общими и статическими методами этого класса, после чего использование этого объекта в качестве прототипа для объектов класса:
function Field(width, height, step, scale){
Drawable.apply(this);
this.width = width || 10000;
this.height = height || 10000;
this.step = step || 50;
this.scale = scale || 1;
for (var i = 0;i<100;i++){
new Food(Math.random()*this.width, Math.random()*this.height, Math.random()*10, colors[Math.floor(Math.random()*colors.length)]);
}
}
Field.prototype = Object.create(Drawable.prototype); //!!!
Field.prototype.constructor = Field;
Field.prototype.draw = function(){
for (var i=0;i < this.width; i += this.step){
ctx.beginPath();
ctx.moveTo(i,0);
ctx.lineTo(i,this.height);
ctx.stroke();
}
for (var i=0;i < this.height; i += this.step){
ctx.beginPath();
ctx.moveTo(0,i);
ctx.lineTo(this.width,i);
ctx.stroke();
}
}