I was looking into the prototype object, and i am a bit confused about the following
//my constructor function
function Circle(r) {
this.radius = r;
this.PI = 3.14;
}
function areaCalculator() {
this.area = this.PI * this.radius * this.radius;
}
function circumferenceCalculator() {
this.circumference = 2* this.PI * this.radius;
}
since our function is an object and has a property called prototype, it is possible to add properties and methods to this prototype object and these would automatically be available for all our custom objects we create using our function constructor.
Circle.prototype.areaCalculator = areaCalculator; //adding function
Circle.prototype.color = "Red"; //adding property
var circle1 = new Circle(5);
circle1.areaCalculator();
console.log(circle1.radius);//5
console.log(circle1.area); //78.5
console.log(circle1.color);//Red
If I understand correctly, all objects using Circle will reference the same color variable unless they are explicitly set. Is this correct?
Also what does it mean to do something like below without using prototype
Circle.circumferenceCalculator = circumferenceCalculator;
Circle.color = "Red";
Are the above two statements correct?
Yes, all the objects created with new Circle will point to the same color property. This property will actually be located on the prototype object, not on the object that you have created. Thus, when you set it on a specific object, it will "shadow" the property from the prototype, but not overwrite it - you can try to delete obj.color after you set it and you'll get the old color back.
Doing Circle.color='red' will simply set the color property on the Circle object (even functions are objects, but they have a callable property which defines their behaviour when called) - this is in no way connected to the Circle's prototype.
A function is also an object and you can augment properties to it. A common example is jQuery, where the $ acts as both an object and a function.
function Circle(r) {}
Circle.circumferenceCalculator = circumferenceCalculator;
Circle.color = "Red";
$.each(); //$ as an object
$('selector').each() //$ as a function
However, this won't reflect in the instance you create. The ones that reflect on the instances are only those that are added via prototype and those in the constructor function.
function Circle(r) {
this.radius = r;
this.PI = 3.14;
}
Circle.prototype.areaCalculator = areaCalculator;
Circle.prototype.color = "Red";
var mycircle = new Circle(5);
//props on Circle itself:
//Circle.color
//Circle.areaCalculator
//props on the instance:
//mycircle.radius
//mycircle.PI
//mycircle.areaCalculator
//mycircle.color
Related
I am new in JS, lets have a look on my code bellow.
I want to change value of legs property of mouse to 2 while using proto but I am unable to change it. All I am getting in output is 4. Please help why is this ?
function Animal() {
this.legs = 4;
}
var mouse = new Animal();
mouse.__proto__.legs = 2;
console.log(mouse.legs);
You can't change instance property this way.
mouse.__proto__ contains constructor function Animal.
If you want to change only mouse's legs you have to do it this way:
mouse.legs = 2
If you want to change every future animals - you unfortunately can't. new Animal() will always reference to original constructor function.
When you call new Animal, the JS engine doesn't reference Animal.prototype.constructor, it uses the Animal as the constructor function and Animal.prototype as the newly created object's prototype, ignoring Animal.prototype.constructor.
As commented, the leg you are trying to access is a self owned property and not on prototype.
Following is a sample:
function Animal() {
this.legs = 4;
}
Animal.prototype.legs = 8;
var mouse = new Animal();
mouse.legs = 2;
console.log(mouse.legs, mouse.__proto__.legs);
That said, if you wish to have a override concept implementation, always remember, never mutate/change property on prototype.
Idea is to have common property on prototype and have custom property on self.
Following is a sample depicting the same:
function Animal() { this.legs = 4; }
function Reptile() { this.legs = 4; }
Reptile.prototype = new Animal();
var mouse = new Reptile();
console.log('Mouse details : ', mouse.legs, mouse.__proto__.legs);
var snake = new Reptile();
snake.leg = 0;
console.log('Snake details : ', snake.legs, snake.__proto__.legs);
snake.__proto__.legs = 0;
console.log('After mutation')
console.log('Mouse details : ', mouse.legs, mouse.__proto__.legs);
console.log('Snake details : ', snake.legs, snake.__proto__.legs);
To simply put, everything in JS is an object. When you create an object, it has 2 nested levels by default:
-> this
-> __proto__
Any property of your constructor goes to this. Any property on its prototype goes to __proto__. Since all objects are inherited from Object, there is a chain till global object.
All JavaScript objects inherit properties and methods from a prototype. Once it gets inherited, you can directly call or change the value of it.
function Animal() {
this.legs = 4;
}
var mouse = new Animal();
// mouse.__proto__.legs = 2;
//instead do this
mouse.legs = 2;
console.log(mouse.legs);
//I have this base Rectangle constructor function
function Rectangle (length, width){
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function (){
return this.length * this.width;
};
//Creating Square constructor function that will inherit from Rectangle...
function Square(size){
this.length = size;
this.width = size;
}
Square.prototype = new Rectangle();
Square.prototype.constructor = Square;
//creating rectangle and square instances
var rect = new Rectangle(5, 10);
var square = new Square(6);
console.log(rect.getArea()); //50
console.log(square.getArea()); //36
console.log(Rectangle.prototype.isPrototypeOf(Square.prototype)); //true
console.log(Rectangle.prototype.isPrototypeOf(rect)); //true
console.log(Square.prototype.isPrototypeOf(square)); //true
my question is when i do the below console.log(), I expected it to print false. However, I got true.
console.log(Rectangle.prototype.isPrototypeOf(square)); //true
1) Does this mean isPrototypeOf goes to multiple levels?
2) if isPrototypeOf goes multiple levels, what is the point of using isPrototypeOf instead of using instanceof?
I've read this Why do we need the isPrototypeOf at all? but didn't understand how it applies in my use-case.
isPrototypeOf checks if an object is within another object's prototype chain so yes it does go multiple levels
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf
They can be used for the same purpose. You can do square instanceof Square or Square.prototype.isPrototypeOf(square) but as you can see, instanceof has a specific purpose to match objects with their constructors where as isPrototypeOf can be used more broadly to check if any object is within the prototype chain of another.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
The isPrototypeOf() method tests for an object in another object's prototype chain
Here in Your Code
console.log(Rectangle.prototype.isPrototypeOf(square)); // true
It prints true because Square Method is in the the chain of
getArea Method and the getArea is the prototype method of Rectangle
Rectangle.prototype.getArea = function (){
return this.length * this.width;
};
For Example According to Mozilla Docs
function Fee() {
// ...
}
function Fi() {
// ...
}
Fi.prototype = new Fee();
function Fo() {
// ...
}
Fo.prototype = new Fi();
function Fum() {
// ...
}
Fum.prototype = new Fo()
Later on down the road, if you instantiate Fum and need to check if
Fi's prototype exists within the Fum prototype chain, you could do
this:
var fum = new Fum();
// ...
if (Fi.prototype.isPrototypeOf(fum)) {
// do something safe
}
I'm learning prototype based OOP in javascript recently. After reading lots of websites explaining the prototype mechanism in javascript, I settle down with this approach from Mozilla
Here are some snippets from Mozilla:
// 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();
rect instanceof Rectangle // true.
rect instanceof Shape // true.
rect.move(1, 1); // Outputs, "Shape moved."
I understand that Rectangle.prototype = Object.create(Shape.prototype); will set the prototype chain properly so that instance of Rectangle will inherit methods from Shape.
But the Rectangle.prototype.constructor = Rectangle; line is a little bit confusing.
From this website I know that when we create a new object like function MyClass(){}, javascript will set its prototype to an empty object and the MyClass.prototype.constructor will point back to MyClass. So Rectangle.prototype.constructor = Rectangle; will fix the broken link since Object.create(Shape.prototype).constructor still points to Shape.
But if I remove this line, I will still get the following code running without a problem. I'm just feeling curious if there's any use case for the constructor attribute? What will go wrong if I just leave it pointing to the super class?
Setting a property this way will make it enumerable(a for in statement would list the constructor property).
var rec = new Rectangle();
'constructor' in rec; //true
You should be using Object.defineProperty or pass in a second argument to Object.create.
Rectangle.prototype = Object.create(Shape.prototype, {constructor: {enumerable: false }});
var rec = new Rectangle();
'constructor' in rec; //
Please refer to this thread for more on the constructor property:
https://stackoverflow.com/a/4013295
In your code it doesn't make any difference, as you still create your object using Rectangle constructor (explicitly using the name of it: var rect = new Rectangle();).
The difference is only in the case, when you've lost reference to object's constructor, or you simply don't know what is it:
// Shape - superclass
function Shape() {
this.x = 1;
this.y = 1;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info(this.x + " " + this.y);
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
//Rectangle.prototype.constructor = Rectangle;
console.info("RECT");
var rect = new Rectangle;
console.info(rect);
console.info(rect instanceof Rectangle);
console.info(rect instanceof Shape);
//console.info(rect instanceof Square); TypeError - Square must be a function, but is still not initialized
rect.move(1, 1);
console.info("RECT2");
var rect2 = new rect.constructor();
console.info(rect2);
console.info(rect2 instanceof Rectangle);
console.info(rect2 instanceof Shape);
// console.info(rect2 instanceof Square); TypeError - Square must be a function, but is still not initialized
rect2.move(1, 1);
console.info("RECT3");
var Square = rect.constructor;
Square.prototype.move = function(x, y) { // just to make it different
this.x *= x;
this.y *= y;
console.info(this.x + " " + this.y);
}
var rect3 = new Square();
console.info(rect3);
console.info(rect3 instanceof Rectangle);
console.info(rect3 instanceof Shape);
console.info(rect3 instanceof Square);
rect3.move(4, 4);
I commented out the line with setting the constructor. Uncomment it to see the difference in output. I have also added another way to use the constructor property - another inheritance example (Square based on Shape but with different move method).
So if you don't fix this link, in the case I showed, you will use Shape constructor, and creation of objects of the same type will become simply impossible. rect was of both types, but rect2 is not anymore.
So assuming, even if you don't need it, it is a very good practice to fix this link to the correct constructor, as someone working with your code in the future may need it.
EDIT:
constructor property doesn't affect anything in the object itself. It's set once object is created to save the reference to the function which created the object. If you will need it in the future than it makes sense to have a correct one. I don't see any other issues.
instanceOf will return true if the object is of the specified object type in its inheritance chain.
It has nothing to do with constructor property.
We can use constructor property if we want to initialize property or execute default code at the time of creation of Object.
For example in your example, if we want to create Rectangle always in red color, we can use constructor of Rectangle as follows:
function Rectangle() {
Shape.call(this); // call super constructor.
this.color = "red";
}
Hope this clear your query.
I am defining a class in JavaScript
function Pen(parent){
this.color = "#0000ff";
this.stroke = 3;
this.oldPt;
this.oldMidPt;
this.isActive = false;
this.parent = parent; //app that owns this pen
this.points = [];
this.curShape;
console.log(this);
return(this);
}
In the console.log statement I am getting way more than just this class, I am getting all kinds of information about basically everything else going on. Why is that?
the keyword this is dependent on the caller, so if you are initializing the function without the "new" keyword "this" might very well be referencing the window and not the object.
Try:
function Pen(parent){
var context = this;
this.color = "#0000ff";
this.stroke = 3;
this.oldPt;
this.oldMidPt;
this.isActive = false;
this.parent = parent; //app that owns this pen
this.points = [];
this.curShape;
console.log(context);
return(this);
}
var pen = new Pen();
Because your "class" inherits (transparently, in your case) from other javascript base classes. If you want to introspect only the properties you've created on your object, use hasOwnProperty(keyName) to filter those out.
Javascript is prototype based and not class based. Every new custom object as default
has pre built functionlity provided by the base object called Object.
So everytime you ask if a property or method belongs to a given object, in the worst
case it will fall until the Object object, and if that property/method is not there
then it will throw an error. Therefore when you are using the log function it is
printing all the object structure including properties and method of its "base" class.
I AM trying to understand js prototype property: my sample code
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
Container.prototype.stamp = function (string) {
return this.member + string;
}
document.write(newc.stamp('def'));
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
var b = new Box();
document.write(newc.test);
here the last line is undefined - even though Container's prototype is a Box and Box's prototype has a property test, why is the newc which refers to test in Box doesnt work? can any one please explain how the 'Prototype' works in my above context.
Thanks...
You are setting Container prototype to Box() after the newc instance was already created.
Reorder the statements as follows:
function Container(param) {
this.member = param;
}
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
Box.prototype.test = "whatever";
Container.prototype.stamp = function (string) {
return this.member + string;
}
//Here the containers prototype setup is complete.
var newc = new Container('abc');
document.write(newc.stamp('def'));
document.write(newc.test);
If sounds like you want to know WHY it is behaving the way it is, and not just "fix" the code. So here's what's going on.
As you saw, if you change the prototype of "Container", you will actually change the properties for new objects AND objects already instantiated. So:
function Container(param) {
this.member = param;
}
var newc = new Container('abc');
// setting a new property of the prototype, after newc instantiated.
Container.prototype.stamp = function (string) {
return this.member + string;
}
// This already-instantiated object can access the stamp function
document.write(newc.stamp('123')); // output: abc123
So there's no problem with the above, as long as you don't call the new method before it's defined. Now the next point. Add this to the above:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
Container.prototype = new Box();
var newd = new Container('fgh');
document.write(newd.stamp('456')); // output: ERROR
Error! But that makes sense, right? You totally wiped out the "Container" prototype and replaced it with the one from "Box", which has no "stamp" function.
I am going to assume you want "Box" to inherit from "Container". That would be logical from the naming convention. If you want to do that, replace the previous section with this:
// Our Box object
function Box() {
this.color = "red";
this.member = "why";
}
// This inherits from Container. Note that we can
// do this before or after we declare "Box"
Box.prototype = new Container();
Box.prototype.test = "Whatever";
var b = new Box("jkl"); // note: "jkl" is ignored because "Box" sets "member" to "why"
document.write(b.test); // output: Whatever
document.write("<br>");
document.write(b.stamp("345")); // output: why345
So now we have a "Box" that can call its own methods and parameters, and also call them from its parent "Container".
So the big picture is that an object will look at its own prototype for a method or something, and if it doesn't find it there it will look in the prototype of the thing it inherited from, and so on. The other big point is that setting something in the prototype makes it immediately available in all future AND current instances of that object.
An object does not contain a reference to its constructor which it uses to get at the prototype. If it did, then the code would work as you expected.
Instead, an object contains a reference to its prototype that is set when it is created.
From the language spec section 4.2.1:
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.