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.
Related
Why does I need use .prototype in Shape.prototype when extends it?
// Shape — superClass
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Figure has rode out somewhere.');
};
function Rectangle() {
Shape.call(this);
}
Rectangle.prototype = Object.create(Shape.prototype);//<<<=HERE
I mean this 'Shape.prototype'.
Why does I need use prototype instead of just Shape? As I know .prototype contains inherited properties and methods of a class. My Shape class is basic and has no inherited properties.
Methods are usually added to the underlying prototype of an object so that they don't have to be stored in each instance that gets made later. That's the case in this example, the move() function is being stored in Shape.prototype.
If you don't use Shape.prototype with Object.create(), you won't get methods attached to that object inherited to Rectangle.
Technically, you could use just Object.create(Shape), but only in situations where Shape only has instance properties attached directly to it and, even in that case, it wouldn't be a very scalable solution, because if you ever decided to go back and add methods to Shape.prototype in the future, none of your sub-types would inherit it.
// Shape — superClass
function Shape() {
this.x = 0;
this.y = 0;
}
// Shape.prototype is a unique and specific instance of Object
// This particular instance is what Shape inherits from and is
// the reason why Shape will get a .toString() and a .valueOf()
// method.
console.log(Shape.prototype);
// This method is added to Shape.prototype. If you don't inherit
// from this, you won't inherit this method!!
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Figure has rode out somewhere.');
};
function Rectangle() {
Shape.call(this);
}
// If we don't inherit from Shape.prototype, we won't get
// any of the methods attached to it!
Rectangle.prototype = Object.create(Shape);
var r = new Rectangle();
console.log(r.x, r.y); // Works just fine for instance properties attached direclty to Shape
r.move(10,20); // Fails because Shape.prototype wasn't used for inheritance!
This question already has answers here:
Why is it necessary to set the prototype constructor?
(14 answers)
Closed 3 years ago.
I haven't been able to find a clear explanation of this. This is a straightforward example that I found on MDN. The only thing I don't understand is why the constructor is set. Can someone explain why this is needed? Is it for inheritance and so that the correct prototype chain is reffered to?
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle);// true
console.log('Is rect an instance of Shape?', rect instanceof Shape);// true
rect.move(1, 1); // Outputs, 'Shape moved.'
Whenever you create a function, say function foo(){}, the JS engine also creates an anonymous object and connects the two in a similar fashion.
foo.prototype = {};
foo.prototype.constructor = foo;
The property names "constructor" and "prototype" are so only because of semantics. It is possible that the standard names were:
foo.ping = {};
foo.ping.pong = foo;
And "the purpose of setting prototype.constructor" is simple - to be able to use the constructor function of that class.
If you don't need to call the constructor function, you can omit the property entirely.
To know more about the topic I recommend reading
http://www.javascripttutorial.net/javascript-prototype/
and
http://www.javascripttutorial.net/javascript-prototypal-inheritance/
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.
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 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);