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.
Related
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/
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>
Recognizing that JavaScript doesn't have the concept of class per se, and that the "type" of all objects is "object", I'm trying to get my head around just what a "prototype" consists of and, in particular, how its "name" is associated with it. For example, in the following:
function Foo(){};
console.log(Foo.prototype); // => "Foo {}"
How does console.log know to output Foo before the braces and what is that name referring to?
(Note: I'm aware that in the above, I'm referring to the prototype property of functions and not the prototype per se (i.e. not the thing accessible by __proto__), but the same question applies to the actual prototype objects. I just used the prototype property to simplify my example.)
Update: Based on the comment thread, this question is really focused on what Chrome is doing and, in particular, rationalizing its behavior in the following:
function Foo(){};
Foo.prototype.constructor = function Bar(){};
f = new Foo();
console.log(f); // => Foo{} (remembering that f created by Foo, ignoring constructor)
console.log(Foo.prototype) // => Bar{} (reporting constructor value)
See https://gist.github.com/getify/5793213 for more discussion.
JavaScript has a very twisted form of prototypal inheritance. I like to call it the constructor pattern of prototypal inheritance. There is another pattern of prototypal inheritance as well - the prototypal pattern of prototypal inheritance. I'll explain the latter first.
In JavaScript objects inherit from objects. There's no need for classes. This is a good thing. It makes life easier. For example say we have a class for lines:
class Line {
int x1, y1, x2, y2;
public:
Line(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
int length() {
int dx = x2 - x1;
int dy = y2 - y1;
return sqrt(dx * dx + dy * dy);
}
}
Yes, this is C++. Now that we created a class we may now create objects:
Line line1(0, 0, 0, 100);
Line line2(0, 100, 100, 100);
Line line3(100, 100, 100, 0);
Line line4(100, 0, 0, 0);
These four lines form a square.
JavaScript doesn't have any classes. It has prototypal inheritance. If you wanted to do the same thing using the prototypal pattern you would do this:
var line = {
create: function (x1, y1, x2, y2) {
var line = Object.create(this);
line.x1 = x1;
line.y1 = y1;
line.x2 = x2;
line.y2 = y2;
return line;
},
length: function () {
var dx = this.x2 - this.x1;
var dy = this.y2 - this.y1;
return Math.sqrt(dx * dx + dy * dy);
}
};
Then you create instances of the object line as follows:
var line1 = line.create(0, 0, 0, 100);
var line2 = line.create(0, 100, 100, 100);
var line3 = line.create(100, 100, 100, 0);
var line4 = line.create(100, 0, 0, 0);
That's all there is to it. No confusing constructor functions with prototype properties. The only function needed for inheritance is Object.create. This function takes an object (the prototype) and returns another object which inherits from the prototype.
Unfortunately, unlike Lua, JavaScript endorses the constructor pattern of prototypal inheritance which makes it more difficult to understand prototypal inheritance. The constructor pattern is the inverse of the prototypal pattern.
In the prototypal pattern objects are given the most importance. Hence it's easy to see that objects inherit from other objects.
In the constructor pattern functions are given the most importance. Hence people tend to think that constructors inherit from other constructors. This is wrong.
The above program would look like this when written using the constructor pattern:
function Line(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
Line.prototype.length = function () {
var dx = this.x2 - this.x1;
var dy = this.y2 - this.y1;
return Math.sqrt(dx * dx + dy * dy);
};
You may now create instances of Line.prototype as follows:
var line1 = new Line(0, 0, 0, 100);
var line2 = new Line(0, 100, 100, 100);
var line3 = new Line(100, 100, 100, 0);
var line4 = new Line(100, 0, 0, 0);
Notice the similarity between the constructor pattern and the prototypal pattern?
In the prototypal pattern we simply create an object which has a create method. In the constructor pattern we create a function and JavaScript automatically creates a prototype object for us.
In the prototypal pattern we have two methods - create and length. In the constructor pattern too we have two methods - constructor and length.
The constructor pattern is the inverse of the prototypal pattern because when you create a function JavaScript automatically creates a prototype object for the function. The prototype object has a property called constructor which points back to the function itself:
As Eric said, the reason console.log knows to output Foo is because when you pass Foo.prototype to console.log:
It finds Foo.prototype.constructor which is Foo itself.
Every named function in JavaScript has a property called name.
Hence Foo.name is "Foo". So it finds the string "Foo" on Foo.prototype.constructor.name.
Edit: Alright, I understand that you have a problem with the redefining the prototype.constructor property in JavaScript. To understand the problem let's first understand how the new operator works.
First, I want you to take a good look at the diagram I showed you above.
In the above diagram we have a constructor function, a prototype object and an instance.
When we create an instance using the new keyword before a constructor JS creates a new object.
The internal [[proto]] property of this new object is set to point to whatever constructor.prototype points to at the time of object creation.
What does this imply? Consider the following program:
function Foo() {}
function Bar() {}
var foo = new Foo;
Foo.prototype = Bar.prototype;
var bar = new Foo;
alert(foo.constructor.name); // Foo
alert(bar.constructor.name); // Bar
See the output here: http://jsfiddle.net/z6b8w/
The instance foo inherits from Foo.prototype.
Hence foo.constructor.name displays "Foo".
Then we set Foo.prototype to Bar.prototype.
Hence bar inherits from Bar.prototype although it was created by new Foo.
Thus bar.constructor.name is "Bar".
In the JS fiddle you provided you created a function Foo and then set Foo.prototype.constructor to function Bar() {}:
function Foo() {}
Foo.prototype.constructor = function Bar() {};
var f = new Foo;
console.log(f.hasOwnProperty("constructor"));
console.log(f.constructor);
console.log(f);
Because you modified a property of Foo.prototype every instance of Foo.prototype will reflect this change. Hence f.constructor is function Bar() {}. Thus f.constructor.name is "Bar", not "Foo".
See it for yourself - f.constructor.name is "Bar".
Chrome is known to do weird things like that. What's important to understand is that Chrome is a debugging utility and console.log is primarily used for debugging purposes.
Hence when you create a new instance Chrome probably records the original constructor in an internal property which is accessed by console.log. Thus it displays Foo, not Bar.
This is not actual JavaScript behavior. According to the specification when you overwrite the prototype.constructor property there's no link between the instance and the original constructor.
Other JavaScript implementations (like the Opera console, node.js and RingoJS) do the right thing and display Bar. Hence Chrome's behavior is non-standard and browser-specific, so don't panic.
What's important to understand is that even though Chrome displays Foo instead of Bar the constructor property of the object is still function Bar() {} as with other implementations:
The constructor property (which refers to a function originally used as a generator of the corresponding objects) is used to give a name to a prototype object in the console log. Consider the following:
function Foo() {
this.x = 1;
}
console.log(Foo.prototype); // Foo {}
Foo.prototype.constructor = function Bar() {
this.y = 2
}
console.log(Foo.prototype); // Bar {}
var f = new Foo();
console.log(f.constructor); // function Bar() { this.y = 2}
console.log(f.x); // 1
console.log(f.y); // undefined
console.log(f); // Foo {x:1}
Here we've switched constructor to another function, giving a new name to prototype object. Note that the same function is returned when constructor property is queried directly from an object, created with Foo() function (as we go up the inheritance chain).
Still, it doesn't mean that another function (Bar()) was actually used to create the corresponding objects; it's still Foo(), and you can see it both by querying properties -- and f directly. Basically, objects remember the function that was used to create them, even if constructor property of prototype was "redirected".
function Foo(){};
Working down the chain:
console.log(Foo.prototype);
console.log(Foo.prototype.constructor);
console.log(Foo.prototype.constructor.name);
Took a bit of digging online but I found this article that really illustrates how prototypes and other key core javascript functionality works:
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
I particularly like the diagram on how the prototype chain looks like.
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.
Help,
I have this class
var jMath = {
pi2: Math.PI,
foo: function() {
return this.pi2;
}
}
I want to make the pi2 constant and i want jMath to inherit from Math object. How do I do that?
Oh amusing, scratch all that, this is the correct version:
function JMath() {
this.foo = function() {
return this.PI;
}
}
JMath.prototype = Math;
var jMath = new JMath();
alert(jMath.foo());
(which matches what the other answer is here)
(I originally tried to set the prototype using "JMath.prototype = new Math()" which is how I've seen it other places, but the above works)
Edit
Here's one way to do it as a singleton
// Execute an inline anon function to keep
// symbols out of global scope
var jMath = (function()
{
// Define the JMath "class"
function JMath() {
this.foo = function() {
return this.PI;
}
}
JMath.prototype = Math;
// return singleton
return new JMath();
})();
// test it
alert( jMath.PI );
// prove that JMath no longer exists
alert( JMath );
Consider using prototype:
function JMath() {};
JMath.prototype = {
pi2: Math.PI,
foo: function() {
return this.pi2;
}
}
var j = new JMath();
j.pi2=44; j.foo(); // returns 44
delete j.pi2; j.foo(); // now returns Math.PI
The difference between this and #altCognito's answer is that here the fields of the object are shared and all point to the same things. If you don't use prototypes, you create new and unlinked instances in the constructor. You can override the prototype's value on a per-instance basis, and if you override it and then decide you don't like the override value and want to restore the original, use delete to remove the override which merely "shadows" the prototype's value.
Edit: if you want to inherit all the methods and fields of the Math object itself, but override some things without affecting the Math object, do something like this (change the name "Constructor1" to your liking):
function Constructor1() {};
Constructor1.prototype = Math;
function JMath() {};
JMath.prototype = new Constructor1();
JMath.prototype.pi2 = JMath.prototype.PI;
JMath.prototype.foo = function() { return this.pi2; }
var j = new JMath();
j.cos(j.foo()); // returns -1
edit 3: explanation for the Constructor1 function: This creates the following prototype chain:
j -> JMath.prototype -> Math
j is an instance of JMath. JMath's prototype is an instance of Constructor1. Constructor1's prototype is Math. JMath.prototype is where the overridden stuff "lives". If you're only implementing a few instances of JMath, you could make the overridden stuff be instance variables that are setup by the constructor JMath, and point directly to Math, like #altCognito's answer does. (j is an instance of JMath and JMath's prototype is Math)
There are 2 downsides of augmenting-an-object-in-the-constructor. (Not actually downsides necessarily) One is that declaring instance fields/methods in the constructor creates separate values for each instance. If you create a lot of instances of JMath, each instance's JMath.foo function will be a separate object taking up additional memory. If the JMath.foo function comes from its prototype, then all the instances share one object.
In addition, you can change JMath.prototype.foo after the fact and the instances will update accordingly. If you make the foo function in the constructor as a per-instance method, then once JMath objects are created, they are independent and the only way to change the foo function is by changing each one.
edit 2: as far as read-only properties go, you can't really implement them from within Javascript itself, you need to muck around under the surface. However you can declare so-called "getters" which effectively act as constants:
JMath.prototype.__defineGetter__("pi2", function() { return Math.PI; });
JMath.prototype.__defineSetter__("pi2", function(){}); // NOP
var j = new JMath();
j.pi2 = 77; // gee, that's nice
// (if the setter is not defined, you'll get an exception)
j.pi2; // evaluates as Math.PI by calling the getter function
Warning: The syntax for defining getters/setters apparently is not something that IE doesn't implement nicely.
User-defined object properties can't be constant. Math (and a few other objects) is a special built-in - it has read-only properties and functions. But it's not a constructor - it's just a static object (Math.constructor === Object).
And because JavaScript has prototypal inheritance, and not classical, you can't inherit from Math. (Read more here)
What you can do, however, is define a prototype. When a property isn't found locally, the JS parser looks for that property on the current object's prototype. altCognito's current solutions shows this very well.
I'm curious about exactly what it is you're trying to achieve. Perhaps something like this is what you want?
var jMath = function()
{
const pi2 = Math.PI;
this.getPi2 = function()
{
return pi2;
}
}
var j = new jMath;
alert( j.getPi2() );