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);
Related
This question already has answers here:
this.constructor.prototype -- can't wholly overwrite, but can write individual props?
(2 answers)
Closed 8 years ago.
I'm working with a fairly simple Point2D data structure I built to be inheritable for say a Point3D in the future and I've followed all the guides and similar questions I can find, but none seem help with my issue.
I've defined Point2D as follows:
function Point2D (px, py)
{
this.x = px;
this.y = py;
Point2D.prototype =
{
constructor: Point2D,
move:function (mx, my)
{
this.x = mx;
this.y = my;
},
translate:function (dx, dy)
{
this.x += dx;
this.y += dy;
}
};
};
I instantiate the object as follows:
var p2d1 = new Point2D(2,3);
Then I call one of the methods as follows:
p2d1.move(1,2);
And the result is:
TypeError: Object #<Point2D> has no method 'move'
I have not idea why my methods don't resolve.
I've messed around with it for a good while and found that I can declare Point2D methods this way and they will work.
Point2D.prototype.move = function () {};
Can anyone explain why they first style of replacing the entire prototype does not work, but adding functions to the existing prototype does work?
When you call new Point() the first time, Point.prototype is still an "empty" prototype. I.e. the instance that is created doesn't inherit any methods.
You change (replace) the prototype after the instance was already created. JavaScript has assign by value, not assign by reference. Quick example:
var a = 5;
var b = {c: a};
a = 10;
b.c is still 5, since assigning to a doesn't change what b.c refers to.
Point2D.prototype.move = function () {};
works because you are not replacing Point2D.prototype, you are simply mutating the existing object.
Overall, assignments to *.prototype should take place outside the constructor:
function Point2D (px, py) {
this.x = px;
this.y = py;
};
Point2D.prototype = { };
I am not sure, but defining the prototype inside the declaration of the "class" is unusual and to me, hard to define exactly how things would be resolved. When doing manual inheritence, I tend to follow more these patterns:
function Foo() {
this.bar = ...
}
Foo.prototype.baz = function() { ... }
OR
function Foo() { ... }
function Bar() { ... }
Foo.prototype = new Bar();
OR
Foo.prototype = {
blah: ...
}
Also I wouldn't usually create a "constructor" property manually, as this is a side effect of setting the prototype, but I know some popular libraries do this. In the middle example above, Foo.prototype.constructor == Bar.
If you really want to warp your brain create a second instance of Point2D and watch it have the move method available and working!
So here is what is happening.
define Point2D class
create instance of Point2D class
create initialization object
create execution context object per new keyword usage
attach prototype to execution context (at this point just Object)
run constructor method
assign value of x
assign value of y
assign new prototype value to Point2D class
what you want to do is to move the prototype setting out to the same scope as the class definition.
Seems I didn't understand the constructor concept, So, I wrote some code to test it. Say you have the code like this:
var test=function(){...}
I know there is a property named constructor in the test.prototype object which point to the test object.
Here comes my question:
Is this property(constructor) only belongs to the prototype object ? or Do all the objects have the constructor property?
And I did another test. the code like below:
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
Rectangle = Object.create(Shape);//inherit from the Shape instead of Shape.prototype
Rectangle.constructor==Function//it is true.
I don't know where does Rectangle.constuctor come from or does it inherit from the Shape? thanks.
Object.create returns an object whose prototype is the object you pass it.
Therefore, since Shape.constructor is Function (Shape is a Function object), Rectangle inherits that.
All, After reading this post, and did some test based on it .
function Shape() {
this.x = 0;
this.y = 0;
};
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.log("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
//Shape.call(this); //call super constructor.
};
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle();
alert(rect.x);
If I commented the code Shape.call(this); in the Rectangle, I found the rect.x is underfined instead of the value 0.
And What make me confused is that I found in the best answer of the Post said:
"In javascript, every object has a secret link to the object which created it,forming a chain. When an object is asked for a property that it does not have,its parent object is asked... continually up the chain until the property is found or until the root object is reached."
So I can't understand why the rect can't found x in the prototype chain. The rect is already inherited form Shape. If the x doesn't exist in the rect, It supposed be found in his parent. right ?
And in my understanding .If using Shape.call(this); , It just add a new x property to the rect, well ,that would not be a code reusing the original x from parents. It just like the override property in the classical inheritance . that is add a new property into the sub class which have the same name and type as the one in the base class..I don't know if my understanding is right , if not . please correct me .Or was I missing something I didn't noticed ? thanks.
Edit
Below is my understanding based on the Thilo and Arun P Johny 's answers. please correct me if it is not right.
Before inheritance happen.
After inheritance executed.
So the x only belong to the instance constructed by Shape. thanks
If you don't call the super constructor, then this.x = 0 is not executed so x remains undefined.
If you wanted it to appear in the prototype, you'd have to say Shape.prototype.x = 0, I think.
So I can't understand why the rect can't find x in the prototype chain.
It's because the prototype does not have x either. It only has move. The x gets assigned to individual instances in the constructor (but only if you call it).
Arun P Johny is right (you should read his comment!)
Try this:
function Shape() {
this.x = 0;
this.y = 0;
};
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.log("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
};
Rectangle.prototype = new Shape();
var rect = new Rectangle();
alert(rect.x);
You can call Shape.call(this); like you did (commented) in your code, but this way it's not a "real" inheritance since you won't be able to use move() in Rectangle.
But the code above is a mishmash of "new" and prototypes and hence very confusing. I guess that what you really want to do is something like this:
var Shape = {
x: 0,
y: 0,
move: function(x, y) {
this.x += x;
this.y += y;
alert("Shape moved: ["+this.x+","+this.y+"]");
}
};
var rect = Object.create(Shape);
alert(rect.x);
rect.move(2,3);
rect.move(1,1);
I need a super-readable version of this super simple inheritance in JavaScript. This is some auto-generated code, where I can't afford to be using external functions or libraries.
What I really want is, assuming Point3d "inherits" from Point, I want something like this:
function Point(x,y) {
this.x = x;
this.y = y;
}
function Point3d(x,y,z) {
Point(x, y);
this.z = z;
}
Except it doesn't actually work:
var pt = new Point3d(230,30,11);
// but x and y are in global scope, they should be in pt.x and pt.y :(
One possible option, would in the code generation duplicate all the members -- but since Javascript is prototype based, I would imagine this is easy to do properly (if I actually knew Javascript)
Thanks
Apply the Point constructor to the Point3d object using .call().
function Point3d(x,y,z) {
Point.call(this, x, y);
this.z = z;
}
http://jsfiddle.net/MSfu5/
The .call method sets the value of this in the function you're calling.
Here we're setting it to the new Point 3d object being constructed.
If there's anything on the Point prototype that Point3d should inherit, you can make the Point3d.prototype object an empty instance of Point.
You need to create an object to begin with.
function Point(x,y) {
return { x: x, y: y }
}
function Point3d(x,y,z) {
var self=new Point(x, y);
self.z=z;
return self;
}
var pt = new Point3d(230,30,11);
I am trying to learn how to work with 'classes' in javascript.
Here is my code:
function Shape(x, y) {
this.x= x;
this.y= y;
}
Shape.prototype.toString= function() {
return 'Shape at '+this.x+', '+this.y;
};
function Circle(x, y, r) {
Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
this.r= r;
}
Circle.prototype= $.extend(true, {}, Shape.prototype);
Circle.prototype.toString= function() {
return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}
var c = new Circle(1,2,3);
alert(c);
Is there a way to define the Shape's toString function inside it's constructor, or it does not make sense in this situation?
Base on my understanding:
When you move .toString() into the constructor then .toString() becomes an explicit member of your instance. hence any call to .toString() will fire that explicit member.
Example: http://jsfiddle.net/paptamas/qDSkj/
But when you define that as a prototype, (in the absence of an explicit member called .toString()), any call to .toString() method will fire .toString() function that is defined for the type of calling object (Circle in your case).
Example: http://jsfiddle.net/paptamas/cbnLB/
In other words, explicit members have priority over prototype definitions and when you say
this.toString = function() ...
you are defining that function as a member of your instance (as oppose to member of your type - which is in a way not optimized as well).
Regards.