Shape class in javascript? - javascript

I am trying to make a little shape helper object to help me with the drawing of shapes on html 5 canvas. So far I have;
var Shape = function (config) {
this.initialize(config);
};
var proto = Shape.prototype;
proto.initialize = function (config) {
this.x = config.x || 0;
this.y = config.y || 0;
this.width = config.width || 0;
this.height = config.height || 0;
this.color = config.color || false;
};
/*
Circle
*/
var Circle = function (config) {
this.initialize(config);
};
proto = Circle.prototype;
proto = new Shape();
But it does not seem to work! When I call to create a new circle like so;
var s1 = new Circle({x: 10, y: 10, width: 10, height: 10, color: "red"});
How can I create a base class Shape that will help set up other shapes and assign some common properties that shapes shall have such as, Circle, Rect ect?
I am trying to learn javascript so if the code is way off please explain why and how I can better it,
thanks.

proto = new Shape();
This assigns the proto variable to refer to a new Shape instance.
It does not affect Circle.prototype, which that variable happened to previously refer to.
Note that you're running the Shape() constructor to initialize the Circle prototype, which is probably not a good idea.
Instead, you can write
Circle.prototype = Object.create(Shape.prototype);
This code will create a new object that inherits Shape.prototype, without running its constructor.

change this lines:
proto = Circle.prototype;
proto = new Shape();
with:
Circle.prototype = new Shape();

Related

Something about prototype in Javascript

I write the Javascript code as follow:
function Shape() {
this.x = 0;
this.y = 0;
}
function Rectangle() {
Shape.call(this); // call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
function Tmp() {
this.a = 0;
this.b = 0;
}
Rectangle.prototype.constructor = Tmp;
var rect = Object.create(Rectangle.prototype);
console.log(rect)
then the output is:
The rect should be initialized by constructor function Tmp.my question is where is the attribution a and b of the object rect which initialized by the constructor function Tmp?
The rect should be initialized by constructor function Tmp
If you want that, you'd do:
Tmp.call(rect);
...after
var rect = Object.create(Rectangle.prototype);
function Shape() {
this.x = 0;
this.y = 0;
}
function Rectangle() {
Shape.call(this); // call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
function Tmp() {
this.a = 0;
this.b = 0;
}
//Rectangle.prototype.constructor = Tmp;
var rect = Object.create(Rectangle.prototype);
Tmp.call(rect);
console.log(rect);
Object.create doesn't call any functions at all, it just creates the object with the given prototype. So neither Rectangle nor Shape nor Tmp is called by doing var rect = Object.create(Rectangle.prototype);.
Or if you also want Rectangle to do its job, replace the Object.create call with:
var rect = new Rectangle();
Tmp.call(rect);
It's very strange to set the constructor property of Rectangle.prototype to Tmp, not Rectangle. I would strongly suggest not doing that. And there's no need to if all you want is for Tmp to initialize an instance. The constructor property of the object referenced by SomeFunction.prototype should be SomeFunction, never anything else.

JS: create a subclass instance from a superclass instance

I know how to create subclass prototypes from superclass prototypes. But what if I already have an instance of the superclass object to make a subclass object from?
Using MDN example for classic OOP in JS:
// Shape - superclass
function Shape(x, y) {
this.x = x;
this.y = y;
}
// Rectangle - subclass
function Rectangle(x, y, w, h) {
Shape.call(this, x, y); // call super constructor.
this.w = w;
this.h = h;
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
What if I already have an instance of a shape and I want to create a rectangle based on that?
function createSquareFromShape(shape) {
var rect = new Rectangle(1, 1);
rect = Object.create(shape);
// rect gets the shape prototype but loses Rectangle
}
I know I can manually copy properties from one object to another but maybe there's a faster and easier way?
Object.create returns a new object with its prototype set to whatever object you passed in as the first parameter to the create method. So you are overwriting your rect variable with a new object.
You won't be able to create a Rectangle object from a Shape object, since you Rectangle is a specialization of your Shape object, Shape does not know in which manner it was specialized.
If you are determined to learn a class based style for JavaScript, I would suggest a function on your Shape "class" (object) which creates Rectangles from it self. Or a factory that can take a Shape and return a Rectangle, along the lines of
var ShapeFactory = {
CreateRectange: function(shape, w, h) {
var rect = new Rectangle();
rect.x = shape.x;
rect.y = shape.y;
rect.w = w;
rect.h = h;
return rect;
}
}
var shape = new Shape(1,1);
var rect = ShapeFactory.CreateRectangle(shape, 1, 1);
I feel that I need to suggest reading this book series https://github.com/getify/You-Dont-Know-JS specifically https://github.com/getify/You-Dont-Know-JS/tree/master/this%20%26%20object%20prototypes and decide for yourself if it is worth learning the class based pattern (this can be a very polarizing topic in the community)

Inheritance with JavaScript and Create Method [duplicate]

I don't understand this behavior in javascript for inheritance I've always seen it defined like so :
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg;
this.hit = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
}
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
function Spaceship(){
console.log("instantiate ship");
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
But in my case, these lines :
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
When I do a console.log(this) in my Spaceship constructor, I can see that the proto property is set to Spaceship instead of GameObject, if I remove them, it is set to GameObject.
And if I use :
Spaceship.prototype = GameObject.prototype;
I have no more problems with that. The reason that this blocks me is that I have another object with an add() method and it checks that the object inerhits of GameObject with this code :
if(object instanceof GameObject)
I don't understand what those two lines can probably change so that inheritance is broken when they are present and I'm not sure doing inheritance the second way is good. Could someone enlighten me about this please ? :)
If you do
Spaceship.prototype = GameObject.prototype;
Then they both refer to the same object, so you might as well have everything in GameObject, if you add something to Spaceship.prototype, it will be added to GameObject.prototype as well. You can easily test it by adding something to Spaceship.prototype after the assignment. For example, in your case you can see that GameObject.prototype.constructor is actually Spaceship.
As for
Spaceship.prototype = new GameObject();
This invokes the constructor which might have undesired side effects, you rather want to use:
Spaceship.prototype = Object.create(GameObject.prototype);
Where the used Object.create functionality here comes down to:
Object.create = function( proto ) {
function f(){}
f.prototype = proto;
return new f;
};
Modern browsers already have the function though.
It was never properly explained why you were getting weird behavior with this.hitBox (I think that's what you were trying to say).
If you do inheritance by invoking the parent's constructor to create a prototype, that parent's constructor is executed once to create an instance of the parent type, and then all instances of the child type will share that one instance as their prototype.
The problem with this is that if that constructor has any lines that assign mutable objects to this, then those objects will be properties on that prototype and any modifications to those objects will be reflected across all instances of the child type:
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 12 (oh noes! what happened)
console.log(sps2.hitBox.x); // 12
(there are other, similar problems with the "call a constructor to make a prototype" approach, but I'll just leave it here on that point)
#Esailija's suggestion to use Object.create(baseObject) is the first step to solving this problem. It creates a new object whose prototype is baseObject, but without the stuff that is set up in the constructor (This is a good thing, but it needs to be accounted for. Read on...).
As I just said, this will create an object where the initialization logic in the parent's constructor has never run, but in most cases that logic is relevant to the object's functionality. So there is one more thing you need to do, which is to have the child constructor call the parent constructor:
function Spaceship(oImg, x, y) {
// call parent constructor on this object and pass in arguments.
// you could also use default values for the arguments when applicable
GameObject.call(this, oImg, x, y);
// remainder of Spaceship constructor...
}
This will ensure that the parent constructor logic runs separately for every new Spaceship, and carries out the necessary initialization tasks.
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg || {width:null, height: null};
this.hitBox = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = this.img.width;
this.hitBox.height = this.img.height;
}
function Spaceship(){
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
Spaceship.prototype = new GameObject();
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 9
console.log(sps2.hitBox.x); // 12

Why is Child.prototype = Object.create(Parent.prototype) so common, which seemingly introduces unnecessary indirection? [duplicate]

I don't understand this behavior in javascript for inheritance I've always seen it defined like so :
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg;
this.hit = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
}
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
function Spaceship(){
console.log("instantiate ship");
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
But in my case, these lines :
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
When I do a console.log(this) in my Spaceship constructor, I can see that the proto property is set to Spaceship instead of GameObject, if I remove them, it is set to GameObject.
And if I use :
Spaceship.prototype = GameObject.prototype;
I have no more problems with that. The reason that this blocks me is that I have another object with an add() method and it checks that the object inerhits of GameObject with this code :
if(object instanceof GameObject)
I don't understand what those two lines can probably change so that inheritance is broken when they are present and I'm not sure doing inheritance the second way is good. Could someone enlighten me about this please ? :)
If you do
Spaceship.prototype = GameObject.prototype;
Then they both refer to the same object, so you might as well have everything in GameObject, if you add something to Spaceship.prototype, it will be added to GameObject.prototype as well. You can easily test it by adding something to Spaceship.prototype after the assignment. For example, in your case you can see that GameObject.prototype.constructor is actually Spaceship.
As for
Spaceship.prototype = new GameObject();
This invokes the constructor which might have undesired side effects, you rather want to use:
Spaceship.prototype = Object.create(GameObject.prototype);
Where the used Object.create functionality here comes down to:
Object.create = function( proto ) {
function f(){}
f.prototype = proto;
return new f;
};
Modern browsers already have the function though.
It was never properly explained why you were getting weird behavior with this.hitBox (I think that's what you were trying to say).
If you do inheritance by invoking the parent's constructor to create a prototype, that parent's constructor is executed once to create an instance of the parent type, and then all instances of the child type will share that one instance as their prototype.
The problem with this is that if that constructor has any lines that assign mutable objects to this, then those objects will be properties on that prototype and any modifications to those objects will be reflected across all instances of the child type:
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 12 (oh noes! what happened)
console.log(sps2.hitBox.x); // 12
(there are other, similar problems with the "call a constructor to make a prototype" approach, but I'll just leave it here on that point)
#Esailija's suggestion to use Object.create(baseObject) is the first step to solving this problem. It creates a new object whose prototype is baseObject, but without the stuff that is set up in the constructor (This is a good thing, but it needs to be accounted for. Read on...).
As I just said, this will create an object where the initialization logic in the parent's constructor has never run, but in most cases that logic is relevant to the object's functionality. So there is one more thing you need to do, which is to have the child constructor call the parent constructor:
function Spaceship(oImg, x, y) {
// call parent constructor on this object and pass in arguments.
// you could also use default values for the arguments when applicable
GameObject.call(this, oImg, x, y);
// remainder of Spaceship constructor...
}
This will ensure that the parent constructor logic runs separately for every new Spaceship, and carries out the necessary initialization tasks.
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg || {width:null, height: null};
this.hitBox = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = this.img.width;
this.hitBox.height = this.img.height;
}
function Spaceship(){
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
Spaceship.prototype = new GameObject();
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 9
console.log(sps2.hitBox.x); // 12

Why wouldn't I use Child.prototype = Parent.Prototype rather than Child.prototype = new Parent(); for Javascript inheritance?

I don't understand this behavior in javascript for inheritance I've always seen it defined like so :
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg;
this.hit = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
}
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
function Spaceship(){
console.log("instantiate ship");
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
But in my case, these lines :
this.hitBox.width = oImg.width;
this.hitBox.height = oImg.height;
When I do a console.log(this) in my Spaceship constructor, I can see that the proto property is set to Spaceship instead of GameObject, if I remove them, it is set to GameObject.
And if I use :
Spaceship.prototype = GameObject.prototype;
I have no more problems with that. The reason that this blocks me is that I have another object with an add() method and it checks that the object inerhits of GameObject with this code :
if(object instanceof GameObject)
I don't understand what those two lines can probably change so that inheritance is broken when they are present and I'm not sure doing inheritance the second way is good. Could someone enlighten me about this please ? :)
If you do
Spaceship.prototype = GameObject.prototype;
Then they both refer to the same object, so you might as well have everything in GameObject, if you add something to Spaceship.prototype, it will be added to GameObject.prototype as well. You can easily test it by adding something to Spaceship.prototype after the assignment. For example, in your case you can see that GameObject.prototype.constructor is actually Spaceship.
As for
Spaceship.prototype = new GameObject();
This invokes the constructor which might have undesired side effects, you rather want to use:
Spaceship.prototype = Object.create(GameObject.prototype);
Where the used Object.create functionality here comes down to:
Object.create = function( proto ) {
function f(){}
f.prototype = proto;
return new f;
};
Modern browsers already have the function though.
It was never properly explained why you were getting weird behavior with this.hitBox (I think that's what you were trying to say).
If you do inheritance by invoking the parent's constructor to create a prototype, that parent's constructor is executed once to create an instance of the parent type, and then all instances of the child type will share that one instance as their prototype.
The problem with this is that if that constructor has any lines that assign mutable objects to this, then those objects will be properties on that prototype and any modifications to those objects will be reflected across all instances of the child type:
Spaceship.prototype = new GameObject();
Spaceship.prototype.constructor = Spaceship;
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 12 (oh noes! what happened)
console.log(sps2.hitBox.x); // 12
(there are other, similar problems with the "call a constructor to make a prototype" approach, but I'll just leave it here on that point)
#Esailija's suggestion to use Object.create(baseObject) is the first step to solving this problem. It creates a new object whose prototype is baseObject, but without the stuff that is set up in the constructor (This is a good thing, but it needs to be accounted for. Read on...).
As I just said, this will create an object where the initialization logic in the parent's constructor has never run, but in most cases that logic is relevant to the object's functionality. So there is one more thing you need to do, which is to have the child constructor call the parent constructor:
function Spaceship(oImg, x, y) {
// call parent constructor on this object and pass in arguments.
// you could also use default values for the arguments when applicable
GameObject.call(this, oImg, x, y);
// remainder of Spaceship constructor...
}
This will ensure that the parent constructor logic runs separately for every new Spaceship, and carries out the necessary initialization tasks.
function GameObject(oImg, x, y) {
this.x = x;
this.y = y;
this.img = oImg || {width:null, height: null};
this.hitBox = new Object();
this.hitBox.x = x;
this.hitBox.y = y;
this.hitBox.width = this.img.width;
this.hitBox.height = this.img.height;
}
function Spaceship(){
GameObject.apply(this, arguments);
this.vx = 0;
this.vy = 0;
this.speed = 3;
this.friction = 0.94;
}
Spaceship.prototype = new GameObject();
var sps1 = new Spaceship();
var sps2 = new Spaceship();
sps1.hitBox.x = 9;
sps2.hitBox.x = 12;
console.log(sps1.hitBox.x); // 9
console.log(sps2.hitBox.x); // 12

Categories