I want to create an instance of a Point with and without the new operator like:
Point(5, 10); // returns { x: 5, y: 10 }
// or
new Point(5, 10); // also returns { x: 5, y: 10 }
I got it working so far with the help of StackOverflow.
function Point() {
if (!(this instanceof Point)) {
var args = Array.prototype.slice.call(arguments);
// bring in the context, needed for apply
args.unshift(null);
return new (Point.bind.apply(Point, args));
}
// determine X and Y values
var pos = XY(Array.prototype.slice.call(arguments));
this.x = pos.x;
this.y = pos.y;
}
But that looks horrible, I am even unshifting null into the array so I can use apply. That just doesn't feel right.
I found a lot of solutions how to achieve it with new constructors and constructor wrappers but I want to keep it as simple as possible (it's just a plain, simple Point).
Is there an easier way to achieve this behaviour?
If you don't mind using ECMAScript 5 functions, Object.create() could help:
function Point()
{ var args = Array.prototype.slice.call(arguments);
if (this instanceof Point) return Point.apply(null, args);
var pos = XY(args);
var result = Object.create(Point.prototype);
result.x = pos.x;
result.y = pos.y;
return result;
}
If you need ECMAScript 3 compatibility, this crazy, convoluted solution is yet another one (note that it's just a wrapper for an internal equivalent of new Point):
function Point()
{ var pos = XY(Array.prototype.slice.call(arguments));
function internalPoint()
{ this.x = pos.x;
this.y = pos.y;
}
internalPoint.prototype = Point.prototype;
return new internalPoint;
}
Related
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
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
I want to create a few instance of this class
var fruit = {
texture: new Image(),
speed: 5,
x: 0,
y: 0,
};
function fruits(speed, x, y)
{
fruit.speed = speed;
fruit.x = x;
fruit.y = y;
return fruit;
};
but when i create new object the all value was overridet by last created object. How can i repair this?
My loop:
var apples = [];
for(var i = 0; i < 10; i++)
{
apples[i] = new fruits(5, Math.floor((Math.random()*775)+1), 0);
apples[i].texture.src = "_img/apple.png";
}
The other answers which are appearing here are just bizarre. Here's the solution:
function fruits(speed, x, y)
{
this.texture = new Image( );
this.speed = speed;
this.x = x;
this.y = y;
};
Notice that the keyword this is used to set attributes. That means that when you call
var apple = new fruits( blah blah );
then apple will be set to a new object which has texture, speed, x and y attributes. There is no need to reference some global object to store these; they are stored in the newly created object itself.
Also I would rename it; the convention is to use singular names and a capital first letter for objects, so Fruit would make more sense (allowing new Fruit(...))
function Fruit( speed, x, y ){
var fruit = {}; // or use some base object instead of {}
fruit.texture = new Image();
fruit.speed = speed || 5;
fruit.x = x || 0;
fruit.y = y || 0;
return fruit;
};
var apples = [];
for( var i=0; i<10; i++ ){
apples[i] = Fruit( 5, Math.floor((Math.random()*775)+1), 0 );
apples[i].texture.src = "_img/apple.png";
}
Douglas Crockford - Power Constructor, 'new', 'this' and more
You got an object here:
var fruit = {
texture: new Image(),
speed: 5,
x: 0,
y: 0, // Note the superflous comma, which might break the code in some IE versions
};
And a function here:
function fruits(speed, x, y) {
fruit.speed = speed;
fruit.x = x;
fruit.y = y;
return fruit;
};
The function modifies above object whenever it is called and returns it.
Now, what you want is a constructor, but you don't have one here.
This, would be a constructor for a new Fruit:
function Fruit(speed, x, y) {
this.texture = new Image();
this.speed = speed || 5; // Note: Using logical OR to emulate default values for the argument
this.x = x || 0;
this.y = y || 0;
// Note: There is no return here!
}
var a = new Fruit(2, 1, 10);
var b = new Fruit(4, 10, 20);
a === b; // Returns false, you got two instances :)
new may have the functionality of being able to create instances of a Function, but you can still override this behavior by returning manually from within the constructor Function.
Also, even if you left out the return fruit in your original code, you would get back an empty instance of fruits since you don't assign any properties to the newly created instance.
In my Fruit example I reference the instance object via the this keyword, so I can assign speed, image, x and y to each instance created.
You might also want to read:
http://bonsaiden.github.io/JavaScript-Garden/#function.constructors
http://bonsaiden.github.io/JavaScript-Garden/#function.this
function fruits(speed, x, y) {
return {
texture: new Image(),
speed: speed,
x: x,
y: x,
}
};
Try such constructor:
function Fruit(speed, x, y) {
return {
speed: speed,
x: x,
y: y
}
}
alert(new Fruit("mySpeed", 1, 2).speed);
I'm a newbie to javascript and I need some help.
I was trying to sum radius by function, but got an undefined error:(
function sumWithFunction(func, number) {
return func() + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, number);
}
function addFivetoIt(func) {
func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy);
The problem is that you're passing a function a reference to another function, and the passed function is therefore losing scope! Here's the offending line:
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, number);
}
JavaScript objects are in some ways simpler than they appear. When you added the getRadius method to the Circle prototype, you were not defining a class method like you would in classical OO. You were simply defining a named property of the prototype, and assigning a function to the value of that property. When you pass this.getRadius as an argument to a static function, like sumWithFunction, the context of this is lost. It executes with the this keyword bound to window, and since window has no r property, the browser throws an undefined error.
Put another way, the statement this.getRadius() is actually saying "execute the function assigned to the getRadius property of this, and execute it in the context of this. Without calling the function explicitly through that statement, the context is not assigned.
A common solution to this is to add an expected argument to any function which receives another function, for context.
function sumWithFunction(func, context, number) {
return func.apply(context) + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius, this, number);
}
function addFivetoIt(func, context) {
func.apply(context,[5]);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, myCircle);
A simpler, but less robust solution would be to declare a function inline that can access a context reference in the local closure.
function sumWithFunction(func, number) {
return func() + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
var me = this;
this.r = sumWithFunction(function() {
return me.getRadius()
}, number);
}
function addFivetoIt(func) {
func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(function(number) {
return MyCircle.increaseRadiusBy(number);
});
But by far the simplest solution is to use a newer feature of ECMAScript, a function method called bind. It is explained well here, including the fact that it is not supported by all browsers. That's why a lot of libraries, like jQuery, Prototype, etc., have cross-browser function-binding utility methods like $.proxy.
function sumWithFunction(func, number) {
return func() + number;
}
function Circle(X, Y, R) {
this.x = X;
this.y = Y;
this.r = R;
}
Circle.prototype.getRadius = function () {
return this.r;
}
Circle.prototype.increaseRadiusBy = function(number) {
this.r = sumWithFunction(this.getRadius.bind(this), number); // or $.proxy(this.getRadius,this)
}
function addFivetoIt(func) {
func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy.bind(MyCircle)); // or $.proxy(MyCircle.increaseRadiusBy,MyCircle)
The tricky thing with this in JavaScript is that it contains the object the function was a property of when it was called by default. So when you pass MyCircle.increaseRadiusBy as a parameter, you then call it as func(), so the function isn't a property of any object. The easiest way to set this is to use the call() function:
function addFivetoIt(func, context) {
// The first parameter to `call()` is the value of `this` in the function
func.call(context, 5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, MyCircle);
The below approach, setting func as a property before calling it, also works. You would never do this in practice because it adds an unnecessary property to context, but it's a good didactic example to show how this works.
function addFivetoIt(func, context) {
context.func = func;
context.func(5);
}
var MyCircle = new Circle(0, 0, 10);
addFivetoIt(MyCircle.increaseRadiusBy, MyCircle);
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