I am trying to create a javascript "class" and it is working somewhat good, but the Engine.tile.draw isn't working as intended. I cannot seem to get it to work inside Engine.start. Is it not possible to create an object and add a function inside it, like I did? How would you guys do it? Any help is appreciated. :)
var EngineClass = ( function () {
var Engine = function () {
this.canvas = document.getElementById('game');
this.handle = this.canvas.getContext('2d');
};
Engine.prototype.start = function (mapData) {
this.tile.draw(mapData);
};
Engine.prototype.tile = {
draw: function (x, y, tile) {
this.handle.fillText(tile, x * 16, y * 16);
};
}
return Engine;
})();
var Engine = new EngineClass();
The comments above saying you shouldn't try to force classes on JavaScript which is a prototypical language are correct.
Technically, the reason this doesn't work is that whenever you invoke a function using dot notation (e.g. something.method()), the function gets invoked with this bound to the left hand side of the dot. So in this case, when you say this.tile.draw(mapData), the tile.draw function gets invoked with this being the tile object, rather than the Engine object as you'd expect.
There are several ways to overcome this but the best advice is to shift your mindset to JavaScript's prototyping system instead of trying to force your class-based mindset on it.
Because this inside draw function will refer to the Engine.prototype.tile object, not what you expected.
Change
Engine.prototype.tile = {
draw: function (x, y, tile) {
this.handle.fillText(tile, x * 16, y * 16);
};
}
to
Engine.prototype.tile = function() {
var self = this;
return {
draw: function (x, y, tile) {
self.handle.fillText(tile, x * 16, y * 16);
};
};
}
And call it like:
Engine.prototype.start = function (mapData) {
this.tile().draw(mapData);
};
It doesn't really work to use sub -bjects like you are here:
Engine.prototype.tile = {
draw: function (x, y, tile) {
this.handle.fillText(tile, x * 16, y * 16);
};
}
The issue is that when you call Engine.tile.draw(), the this pointer inside the draw() method will be set to the tile object which is not what your code is assuming (your code assumes that this points to the Engine instance which is not what happens).
If you really want a sub-object like this, then you will need to intialize that sub-object in the Engine constructor so that each tile object is set up uniquely and then you will need to add its engine pointer to the tile instance data so that when Engine.tile.draw() is called, you can get the appropriate Engine instance from the this pointer that points to the tile object. But, this is all a mess and probably both unnecessary and the hard way of doing things.
You should probably either make tile its own object with its own instance data or put the draw method on the Engine object and just pass it some arguments that help it do its job.
Related
Given the following code:
var House = function(x, y) {
var _posX;
var _posY;
function init(x,y) {
_posX = x;
_posY = y;
}
// Auto init
init(x, y);
// Public
return {
posX: _posX,
posY: _posY,
setPosition: function(x, y) {
_posX = x;
_posY = y;
}
};
};
If I create a new House object:
var house = new House(3,4);
And use the setPosition method to change the position:
house.setPosition(100,50);
I expected that the house position would still be 3,4.. But it however changed (which is actually what I want, but I don't understand how this is possible?) I dont'understand it since Javascript already returned the position which is 3,4 and I would expect it to be like that all the time, even if I change the position using the set method.
console.log(house.posX + ',' + house.posY); // 100,50 (why not 3,4?)
Bonus question: is there a proper way to do the init rather than placing it, ugly in the middle of the code?
This behaviour is due to a closure.
Closures are functions that refer to independent (free) variables
(variables that are used locally, but defined in an enclosing scope).
In other words, these functions 'remember' the environment in which
they were created.
_posx and _posy were defined in a surrounding scope and setPosition remembers it.
By the way, I think that init should be removed and you should directly assign _posx and _posy in your constructor function.
I have an object like so:
var x = {
"fx": function() {...}
}
I have the name of the object (y = "x") and the function (z = "fx") and have them as strings.
I know I can call the function through the use of eval through the following method or similar:
eval(y.z)
However, I would like to avoid using eval to accomplish this. I know the apply prototype method takes a function and applies it to an object, however searching for the function reference is impossible as the function is contained within the object.
I know this problem is not a new one and hence must have a solution, but I cannot find it. Any help would be appreciated.
You can use
x[y]()
to call the function with a variable
What I've understood is that y and z are some variables and you want to call z method of y object using these variables.
It can be accomplished by various ways. For instance:
(function () {
x = {
"fx": function () {
alert("Hey!");
}
}
y = "x";
z = "fx";
this[y][z]();
}());
DemoFiddle
I know little bit C# and now I have started working with JavaScript and I got some problems in understanding the fundamentals.
Here is my code sample:
function BaseFunc(x, y) {
this.X = x;
this.Y = y;
}
function DerivedFunc(x, y, z) {
this.Z = z;
BaseFunc.call(this, x, y);
}
DerivedFunc.prototype = new BaseFunc;
function Test() {
var d = DerivedFunc(1, 2, 3);
var b = new BaseFunc(4, 5);
d.sayHello();
b.sayHello();
}
DerivedFunc.prototype.sayHello = function () {
alert("Result is: " + (this.X + this.Y + this.Z));
}
In the above code I am trying to make an inheritance.
Everything looks good until I reach the line BaseFunc.call(this, x, y); this line is supposed to call base function but what is the use of this in this context.
Is it just to satisfy the signature of method call, how does it work ?
Second question is, in javascript we can add anything dynamically,
In my case I am adding a sayHello() property and assigning it with an anonymous function.
like DerivedFunc.prototype.sayHello, am I adding a property/method to BaseFunc or DerivedFunc, as it is added to prototype it should be added to BaseFunc as I understand it. But when I execute the above code I get error that sayHello is not defined.
Can someone please clarify me about what is going wrong, thanks?
Everything looks good until I reach the line BaseFunc.call(this, x, y); this line is supposed to call base function but what is the use of this in this context.
It's there so that within the call to BaseFunc, this has the same value it has in the call to DerivedFunc, so that the lines this.X = x; and such in BaseFunc are assigning to the correct instance. (Calling a function setting a specific value for this is what the .call and .apply methods of functions do.)
But when I execute the above code I get error that sayHello is not defined.
If it's d.sayHello where you're having the trouble, it's because you've missed out the new operator on the line d = DerivedFunc(1, 2, 3);. Since DerivedFunc, when just called as a function and not via new, doesn't have any return value, d will be undefined.
Note that the way you're doing inheritance, though common, has issues. The main issue is here:
DerivedFunc.prototype = new BaseFunc;
You're trying to use a function designed to create instances, and which accepts arguments, in order to create the prototype instance that DerivedFunc will assign to things. What then is BaseFunc supposed to do about the arguments that are missing? Then later, you call it again (from DerivedFunc) to initialize the instance. BaseFunc is doing double-duty.
Here's how you correct that, first the long-winded version:
function x() { }
x.prototype = BaseFunc.prototype;
DerivedFunc.prototype = new x;
DerivedFunc.prototype.constructor = DerivedFunc;
Or if you can rely on ES5's Object.create:
DerivedFunc.prototype = Object.create(BaseFunc.prototype);
DerivedFunc.prototype.constructor = DerivedFunc;
Now we're not calling BaseFunc to create the prototype, but we are still getting its prototype object as the underlying prototype of DerivedFunc's prototype object. We no longer have the problem of what to do with BaseFunc's arguments, and BaseFunc is only called in the way it's designed to be called: To initialize individual instances, not prototypes.
Naturally, rather than writing that for every time we want to have derived constructors, you'd have a helper script for it.
If you're interested in JavaScript inheritance hierarchies, you may want to look at my short Lineage script — not necessarily to use, but to understand how these things work. The page showing how to do things without the script and comparing to doing them with the script may be particularly useful.
Hi please go through the following. I hope it will give you some idea about inheritence and call()
<script type="text/javascript">
//inheritence
function parent() {
this.add = function (a, b) {
return a + b;
}
this.subtract = function (a, b) {
return a - b;
}
}
function child() {
this.display = function () {
alert(this.add(11, 23));
}
}
child.prototype = new parent(); //child extends parent.... inheritence
child.prototype.constructor = child; //resetting constructor property
var obj = new child();
obj.display();
/*
.call() and .apply()
They allow our objects to borrow methods from other objects and invoke them as their own
*/
var person = {
name: 'Kundan',
display: function(name) {
alert(this.name + ' welcomes ' + name);
}
};
person.display('Dipa'); //Kundan welcomes Dipa
var person1 = { name: 'Java Master' };
person.display.call(person1, 'Sachin'); //Java Master welcomes Sachin
//here person1 object is passed in the call function
//if we are using call inside a function and want to pass the same function object then this is passed in call function
/*
We can pass more parameters as follows
person.display.call(person1, 'a', 'b', 'c');
The method apply() works the same way as call() but with the difference that all parameters you want to pass to the method of the other object are passed as an array.
*/
person.display.apply(person1, ['a', 'b', 'c']);
</script>
I have a Class that has a private variable with a public setter/getter function:
function Circle(rad) {
var r = rad;
this.radius = function(rad) {
if(!arguments.length) return r;
r = rad;
return this;
}
}
var shape = new Circle(10);
console.log( shape.radius() ); // 10
shape.r = 50;
console.log( shape.radius() ); // 10
How can I replicate this using Object.prototype? Or, when would I want to use a closure instead of Object.prototype? This is the closest I could come up with, but as you can see, you can change the property directly.
function Circle(r) {
this.r = r;
}
Circle.prototype.radius = function(r) {
if(!arguments.length) return this.r;
this.r = r;
return this;
};
var shape = new Circle(10);
console.log( shape.radius() ); // 10
shape.r = 50;
console.log( shape.radius() ); // 50
If you're going to use the prototype to store an object's properties, they are accessible from any code that has a reference to the object. It's impossible to do what you want.
What many JS devs do is just name private properties with a leading underscore so that others know not to mess with it, but it doesn't give you any real protection beyond a suggestion
Reasons to use closure based approach
True private variables, be confident that no one will mess with your privates
Reasons to use prototype
Less memory used (no closures for every instance)
Easier to debug (properties are visible on the object itself)
Allows monkey patching
Readers: Please edit the answer with reasons for whatever you think is the best solution.
I find your first Circle very odd. If you re-write it like this:
function Circle(rad) {
var r = rad;
this.radius = function(rad) {
if(rad){r = rad;}
return r;
}
}
I think it now does what you mean. r is private and radius acts as a getter/setter function.
Setting r like this:
shape.r = 50;
doesn't make sense because your first Circle doesn't have a property r, it only has a locally scoped variable r. It should raise some kind of error.
I can't see a way of using prototype in your second version of Circle because the function in the prototype chain wouldn't have access to a variable created in the Circle object. And anyway, in your second version, r is a property of Circle not a privately scoped variable in the function body.
I am wondering whether it is possible to inherit constructor in javascript. In the following example, I'd like the Moveable to assign x and y arguments to this.x and this.y respectivelly, as I defined in Sprite. Also, what would be the best way (but still short and readable) to define the prototype without creating the instation of ancestor? It would be best to assign it in the class itself, not in the outside scope as I it is now:
function Sprite(x, y) {
this.x = x ? x : 0;
this.y = y ? y : 0;
this.getPos = function() {
return {
x: this.x,
y: this.y
};
};
}
function Moveable(x, y) {
}
Moveable.prototype = new Sprite();
The standard way to call a superclass constructor is using Function.call:
function Moveable(x, y) {
Sprite.call(this, x, y);
}
As for the prototype, you can do something like this to chain the prototype without creating an instance of the superclass:
function makePrototype(superclass) {
function f() { }
f.prototype = superclass.prototype;
return new f();
}
Moveable.prototype = makePrototype(Sprite);
This uses a dummy constructor to create an object that shares the same prototype as Sprite, and since that's all JavaScript cares about, instances of Moveable are considered instanceof Sprite.
This isn't "short and readable" as you asked for, but the only other choice is to entirely skip prototypes and assign members directly within the constructor.
Edit: As #Raynos points out, you also want to set the constructor property (which is done by default by JavaScript but is lost as soon as you reset Moveable.prototype):
Moveable.prototype.constructor = Moveable;
You'd call the parent constructor like this:
function Moveable(x, y) {
Sprite.call(this, x, y);
}
I'm afraid there's no short way of setting up the inheritance if you want to use pseudo-classical inheritance, and no way of doing it inside the scope of the constructor function.
You can get around instantiating your base class though, if you construct a temporary empty object. Looks complicated but is commonly used as a helper function (like in the Google Closure Library goog.inherits method from where I more or less copied this):
var inherits = function(childConstructor, parentConstructor) {
function tempConstructor() {};
tempConstructor.prototype = parentConstructor.prototype;
childConstructor.prototype = new tempConstructor();
childConstructor.prototype.constructor = childConstructor;
};
inherits(Moveable, Sprite);
// instantiating Moveable will call the parent constructor
var m = new Moveable(1,1);
Think of a function as two pieces: the constructor function and the prototype object. Take two of these function classes and mix them together. Mixing the objects are simple enough, the trick is to mix the constructors.
var Sprite = function(x, y, w, h){
console.log("Sprite constr:", x, y, w, h);
}
var Moveable = function(x, y, w, h){
console.log("Moveable constr:", x, y, w, h);
}
var extend = function(class1, class2){
// here we make a new function that calls the two constructors.
// This is the "function mix"
var f = function(){
class1.prototype.constructor.apply(this, arguments);
class2.prototype.constructor.apply(this, arguments);
}
// now mix the prototypes
f.prototype = library.objectmix(class1.prototype, class2.prototype);
return f;
}
var MoveableSprite = extend(Sprite, Moveable);