I'm studying prototypes right now and think that I'm almost there but I'm a bit confused on one topic.
Let's say we have:
function Animal(name, gender) {
this.name = name;
this.gender = gender;
}
function Cat(species) {
this.species = species;
}
Cat.prototype.color = null;
Cat.prototype = new Animal();
My question is, why is prototype needed at all for new properties?
Why couldn't we do:
Cat.color = null;
EDIT::
All the white blocks are from a uml diagram from another SO post. I added the orange boxes to suit this example that I've provided. Does this diagram I've added to still make sense?
My main problem I believe is that I was making the function constructors and the actual prototype objects too similar when in fact they're completely different things. One's a function and one's an object.
EDIT 2
With this diagram, I'm trying to clarify how the constructor property interacts and what it is exactly connected to, and more specifically, how it affects the use of this. Any comments on the validity would help.
Good question:
Cat.color = null; sets the color only on that one Cat, if you put it on the prototype any 'Cat' you instantiate afterwards will also contain a color property.
Lets say you have something like var tabby = new Cat('feline') with the code above it without the prototype tabby won't have a color.
"Everything in Javascript is an Object"
Ever wonder why you can use .toString() on say the number 50 without having written Number.toString = function(){....?
Because it's built-into Javascript. All Number.prototypes have the .toString method. And the list goes on for Arrays, Objects, Strings, etc.
Every time you write a Number in JS, imagine (no constructor is really called) calling a Number constructor function similar to your constructor functions for Animal & Cat.
That's what constructor functions do. They create an instance of (theirname).prototype. That's why function Animal() makes something of Animal.prototype and so on.
function Animal() and function Cat() otherwise have nothing to do with Animal.prototype and Cat.prototype. If you actually made a new Animal with new Animal() and then changed the constructor, the new Animal you just made wouldn't be updated, because it was constructed before the constructor changed.
Let's say you make a Cat "Hobbes"
Then after that, when you say Cat.prototype.color = null;, you're saying all objects of Cat.prototype should have a 'null' value for color. This will update Cats you constructed before, since now when you try to find Hobbe's color, it will spit undefined since you didn't give a color to Hobbes himself in function Cat(), but then JS will backtrack to Hobbe's Cat.prototype and find that color is actually null.
Hope that helps.
Several things to remind;
A constructor function is used to instantiate new objects. If a constructor function has variables defined with a preceding this. keyword then those will be the properties of the instantiated object. The variables defined with preceding var keyword won't be a part of the instantiated object.
The objects instantiated by a constructor function will have their prototypes assigned to the constructor function's prototype hence they have direct access to the constructor function's prototype. This means they can use (share) the properties and functions within the constructor function's prototype as if they are their own.
The prototype is very useful when you think of instantiating thousands of objects from a constructor function. The unique properties of each object such as name, id, color or whatever should be defined with a preceding this. in the constructor. Such as this.name or this.color however the functionalities that they are expected to share should be defined in the constructors prototype since obviously it would be a waste of memory to reserve a room for them within each instantiated object.
Related
I am confuse bit by going through multiple website tutorials and now can't find the difference between below two statements; (Suppose Person a super class/function of Employee)
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
As i know first line show an Employee REFERENCE pointed to Person constructor. And constructor of Person was created by Object.create().
And Second is simply created a Employee constructor.
Let me know if am right as am a java programmer and found javascript is confusing.
The prototype in javascript is like classes in java. So the code:
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Means:
class Employee inherits new Person() { // meaning of first line
Employee constructor = Employee // meaning of second line
}
In classical javascript, there are no classes, instead there are constructors. And a constructor is just a regular function that you call via new myFunction() instead of myFunction().
And instead of a constructor belonging to a class, in javascript a prototype (class-like object) is a property of a constructor. And yes, functions are objects just like any other thing in javascript so they can have properties just like any other object.
Also, in javascript constructors cannot inherit from constructors (don't be silly :D ). Instead, constructors inherit from objects (strictly speaking, objects inherit from objects since the inheritance happens when you call the constructor). That's why we create an instance of the superclass object - to make it an object so we can inherit.
Technically speaking, the line Employee.prototype.constructor is not necessary. The first line is all that's needed to set up inheritance.
While going over frontend master, I got little confused w/ below.
Can someone tell me if there is any difference? (in creating Object Chordate and Chordate2 and Chordate3?). HOw do they fundamentally differ??
I thought always doing newObject = new constructor is the way to build new object in javascript but this newObject.prototype = new Constructor threw me off.
Animal = function(name){this.name = name};
Animal.prototype.eats = function(){
return this.name + " is eating"
}
Chordate = function(name){this.name = name;}
Chordate.prototype = new Animal();
Chordate2 = function(name){this.name = name;}
Chordate2 = new Animal();
Chordate3 = new Animal();
-- my own answer --
Probably I need to watch more videos (as I assume they will say this is not recommended but I do understand how this works now. Here was my confusion and clarification.
Every function(which is another object) that gets created is pointed to it's own prototype(basically object)
Chordate which is already an object and has it's own prototype pointed to it's own object(prototype), this line(Chordate.prototype = new Animal();) is changing .prototype point to Animal prototype.
(which does look hacky, and I need to read and watch more).
So, based on that Chordate2's prototype is also it's own prototype and when you run new Animal on it, it just erases that and only Animal.prototype exists.
Same w/ (except Chordate3.prototype never existed) Chordate3.
Can someone please verify this for me?
That's how inheritance originally works in javascript (and even with classes, the underlying mechanism is still the same).
Basically Chordate is a subclass of Animal. In other languages we'd write:
class Chordate extends Animal {
}
In javascript constructors inherits from objects. Since Animal() is a constructor we need to convert it to an object. So in javascript we do:
Chordate.prototype = new Animal(); // extend Animal
The prototype property holds a prototype or template for how the object created by a constructor should look like. In this case the object created by Chordate should look like an Animal object. When you call new Chordate() the prototype will be copied into this and will be returned as a new instance.
Chordate2 and Chordate3 are just instances of Animal. From the code and the naming of the objects they look like confused code by someone not familiar with javascript. I'd personally expect something like chordate2 = new Chordate().
The first Chordate assignment "Chordate=function(name){this.name=name;} is assigning a constructor identical to that of Animal, and then the next line adds the Animal() constructor to the Chordate object.
Then Chordate2 starts off with a constructor assignment and then is overwritten as an Animal object with an undefined name attribute since no argument was passed to the constructor.
Finally Chordate3 is just an Animal object with an uninitialized name attribute as well.
I do feel funny about responding to my own question and putting it as an answer but as #torazaburo suggested and it would be good for me to get critic as someone who actually provides an answer(up until now, I have only asked) even if it’s wrong so here it goes:
Part of the confusion came as to what below actually is
Object.prototype
I fully understand that when function is created(Animal), it points to its own prototype(which in turn points to base Object(of it’s own prototype(this is found by going up the proto chain).
when Chordate function was created, it was pointing to it’s own
prototype. However, when Chordate.prototype = new Animal was ran, it
essentially overwrote it’s own prototype and pointed to Animal’s
prototype. Whether this is not recommended or not, I am eager to find
out why. I guess I was more focused on learning how this
Object.prototype works and what the relationship was to otherObject(in
this case Animal) being created.
When Chordate2 is ran,
1)it creates a function and have it point to it’s own prototype
2)when you run new Animal() = Chordate2, it essentially erases Chordate2 and creates a brand new object and
only prototype remains is Animal.prototype. Chordate2’s relationship to that is found through __proto__
Same concept w/ (except Chordate3.prototype never existed) Chordate3.
I'm want to understand how and why are prototypes useful in Javascript. After I thought I knew what was going on, I stumbled with the fact that a prototype is just an object and can't be "shared" by many objects in the way I thought. Let me elaborate with an example:
var SpritePrototype = {
img: null,
pos_x: 0,
pos_y: 0,
draw: function(context2d) {
/*do stuff with the canvas
using "this" to refer to
the object this method is
being called on*/
},
//Some more member functions...
}
From the concept of "objects inheriting from objects" that's usually advocated with prototype-friendly Javascript, I thought I could just do:
var player = Object.create(SpritePrototype);
But it turns out this approach is flawed, because the non-function fields will be the ones from SpritePrototype, as player's prototype is exactly SpritePrototype. That means I can't create more objects from that prototype or the non-function fields will get all mixed up.
So what's the point in Object.create, and more important, what would be the correct way to achieve what I'm trying to do? That is, how can I make "player" get a copy of the fields and inherit the functions from its prototype?
Again, I'm interested in doing things the way they're intended to be. I can always simulate inheritance by hand or skip it altogether. The point of my question is to understand prototypes and how and when they are useful, especially in my specific case.
Property values on prototypes are shared initially, but stop being shared when that property on an instance is written (assigned) to. At that moment, the instance gets its own version of the property. So it is not entirely correct to say the value is "shared". It is shared only up to the point in time at which the property on the instance is assigned to.
var SpritePrototype = {
img: 'img1'
};
var sprite1 = Object.create(SpritePrototype);
var sprite2 = Object.create(SpritePrototype);
sprite1.img = 'img2'; // does NOT affect prototype or sprite2
console.log(sprite2.img);
< "img1"
When img is referenced, its value is taken from the prototype. However, when img is written to, a new property is created on the instance to hold the new value, and used from then on.
The only way to change the property value on the prototype is to do so explicitly:
SpritePrototype.img = 'img3';
This will change img for all instances which have not yet defined their own local version of img by assigning to it.
You problem is, that you had defined "static" members in terms of object oriented design. Everything in protoype section is shared between objects. Function doesn't get actually copied to newly created object, but it is called with proper "this".
You should initialize your variables in constructor, like this
function Sprite(...) {
this.img = null;
...
}
Then for subtype you should use Object.create to create a prototype to inherit its methods, so
Player.prototype = Object.create(Sprite.prototype);
And finally, you may call parent constructor to initialize the variables
function Player(...) {
Sprite.call(this, ...);
}
PS. Constructor should be before Player.prototype assigning.
PPS. For more info see this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
In the past when creating "classes" in JavaScript, I have done it like this:
function Dog(name){
this.name=name;
this.sound = function(){
return "Wuf";
};
}
However, I just saw someone do it like this instead:
var Dog = (function () {
function Dog(name) {
this.name = name;
}
Dog.prototype.sound = function () {
return "Wuf";
};
return Dog;
})();
Can you do it both ways, or is the way I've done it wrong? In that case, why? And what exactly is the difference between the two in terms of what we end up with? In both cases we can create an object by saying:
var fido = new Dog("Fido");
fido.sound();
I hope someone will enlighten me.
There are two important differences between your way and theirs.
Wrapping in a self invoking function ((function() { ... })();)
Using the .prototype property over this. for methods.
Wrapping things in a self invoking function, then assigning the result (as defined in the return statement to a variable is called the module pattern. It's a common pattern to ensure scope is more controlled.
Using Dog.prototype.sound = function() {} is preferable to this.sound = function(). The difference is that Dog.prototype.sound is defined once for all objects with the Dog constructor, and the this.sound = function() {} is defined again for each Dog object created.
The rule of thumb is: Things that are individual to an object (usually its properties) are to be defined on this, while things that are shared to all objects of the same type (usually functions) are to be defined on the prototype.
With your code, you're creating a new function sound for every new Dog instance that's being created. Javascript's prototype avoids this by creating only a single function which all object instances share; basically classical inheritance.
In the second code you're showing that's just additionally wrapped in an IIFE, which doesn't do much in this case.
The first is the traditional method of creating a constructor. The second an immediately invoked function expression that returns a constructor. This method allows you to keep variables within the module without leaking out into the global scope which could be an issue.
And what exactly is the difference between the two in terms of what we end up with?
They both, as you've seen, have the same result. The others have talked about prototype so I won't mention it here.
The second is preferable because it takes advantage of Javascript's prototypal inheritance mechanism.
Prototypes
Javascript inheritance is a cause of confusion, but it's actually fairly simple: every object has a prototype, which is an object that we will check when we try to access a property not on the original object. The prototype will, itself, have a prototype; in a simple case, like Dog, this will probably be Object.prototype.
In both of your examples, because of how the new operator works, we will end up with a prototype chain that looks like this: fido->Dog.prototype->Object.prototype. So, if we try to look for the name property on Fido, we'll find it right there on the object. If, on the other hand, we look for the hasOwnProperty property, we'll fail to find it on Fido, fail to find it on Dog.prototype, and then reach Object.prototype, where we'll find it.
In the case of sound, your examples define it in two different places: in the first case, fido and every other dog we create will have their own copy of the function. In the second case, Dog.prototype will have a single copy of the function, which will be accessed by individual dogs when the method is called. This avoids wasting resources on storing duplicates of the sound function.
It also means that we can extend the prototype chain; maybe we want a Corgi class that inherits the sound function from Dog. In the second case, we can simply ensure that Dog.prototype is in Corgi.prototype's prototype chain; in the first, we would need to create an actual Dog and put it in the prototype chain.
Having a Java-background, when I switched to Javascript, I (lazily) tried to stick with what I knew regarding oop, i.e. a classical inheritance. I'm working on a web-app (that I made), and used this kind of inheritance. However, I'm considering to change my code and rewrite the OOP parts to do prototypal inheritance (two reasons: I read a lot that it's better, and secondly, I need to try the other way in order to have a better understanding of it).
My app creates data visualisations (with D3js, but it's not the topic), and organised my code this way:
function SVGBuilder( dataset ) {
this.data = dataset;
this.xCoord;
this.startDisplaying = function() {
// stuff
this.displayElement();
}
}
The displayElement() method is defined in "classes" inheriting from SVGBuilder (which is more or less an abstract class). I then have:
function SpiralBuilder( dataset ) {
SVGBuilder.call( this, dataset );
this.displayElement = function() {
// stuff
};
}
SpiralBuilder.inheritsFrom( SVGBuilder );
I have several other "builders" based on the same structure.
The script calling the builder looks like this (it's a bit more complicated since it select the correct constructor based on the user input):
var builder = new SpiralBuilder( data );
builder.startDisplaying();
Now come the "conversion part". I read quite a lot about this, from Douglas Crockford's article, to parts of the Eloquent Javascript. In Aadit M Shah's comment, he proposes a structure which would look like this:
var svgBuilder = {
data: [],
xCoord: 0, // ?
create: function( dataset ) {
var svgBuilder= Object.create(this);
svgBuilder.data = dataset;
return svgBuilder;
},
startDisplaying: function() {
// stuff
}
}
However, at this point, I'm stuck. Firstly (technical question), can I declare variables (data, xCoord) without initialising them in this pattern? Just like a this.data;? Secondly, how am I then suppose to create the inheritances? I simply manually put the corresponding functions in the prototype? Something like:
var spiralBuilder = builder.create( dataset );
spiralBuilder.prototype.displayElements = function() {
// Code to display the elements of a spiral
};
spiralBuilder.displayElements();
If I am correct, this mean that in the script calling the builder, instead of selecting the correct constructor (which won't exist anymore), I'll have to add/modify the methods in the prototype of a single builder instance. Is it how things should be done?
Or should I try to design my code in a completly different way? If it's the case, could you give me some advices/references for this?
can I declare variables (data, xCoord) without initialising them in this pattern?
var svgBuilder = {
//removed data here as it's only going to shadowed
// on creation, defaults on prototype can be done
// if value is immutable and it's usually not shadowed later
create: function( dataset, xcoord ) {
var svgBuilder= Object.create(this);
svgBuilder.data = dataset;//instance variable
svgBuilder.xcoord = xcoord;//instance variable
return svgBuilder;
},
startDisplaying: function() {
// stuff
},
constructor : svgBuilder.create
};
I know I rarely do this in my samples but when creating instances or invoking functions it is generally better to pass parameter objects.
At some point in time you may change things here or there and you don't want to change many places in your code.
In the first couple of examples you're not using prototype at all. Every member is declared as this.something in the constructor function so is an instance specific member.
A builder can be used but when you're comfortable declaring your constructor functions, your prototype, mix ins and maybe statics then all you need is a helper function for inheritance and mix ins.
Introduction to prototype can be found here. It also goes into inheritance, mix ins, overriding, calling super and the this variable. A copy of the introduction follows:
Constructor function introduction
You can use a function as a constructor to create objects, if the constructor function is named Person then the object(s) created with that constructor are instances of Person.
var Person = function(name){
this.name = name;
};
Person.prototype.walk=function(){
this.step().step().step();
};
var bob = new Person("Bob");
Person is the constructor function as it's an object (as most anything else in JavaScript) you can give it properties as well like: Person.static="something" this is good for static members related to Person like:
Person.HOMETOWN=22;
var ben = new Person("Ben");
ben.set(Person.HOMETOWN,"NY");
ben.get(Person.HOMETOWN);//generic get function what do you thing it'll get for ben?
ben.get(22);//maybe gets the same thing but difficult to guess
When you crate an instance using Person you have to use the new keyword:
var bob = new Person("Bob");console.log(bob.name);//=Bob
var ben = new Person("Ben");console.log(bob.name);//=Ben
The property/member name is instance specific, it's different for bob and ben
The member walk is shared for all instances bob and ben are instances of Person so they share the walk member (bob.walk===ben.walk).
bob.walk();ben.walk();
Because walk() could not be found on bob direcly JavaScript will look for it in the Person.prototype as this is the constructor of bob. If it can't be found there it'll look on Function.prototype because Person's constructor is Function. Function's constructor is Object so the last thing it will look is on Object.prototype. This is called the prototype chain.
Even though bob, ben and all other created Person instances share walk the function will behave differently per instance because in the walk function it uses this. The value of this will be the invoking object; for now let's say it's the current instance so for bob.walk() "this" will be bob. (more on "this" and the invoking object later).
If ben was waiting for a red light and and bob was at a green light; then you'll invoke walk() on both ben and bob obviously something different would happen to ben and bob.
Shadowing members happens when we do something like ben.walk=22, even though bob and ben share walk the assignment of 22 to ben.walk will not affect bob.walk. This is because that statement will create a member called walk on ben directly and assign it a value of 22. There will be 2 different walk members: ben.walk and Person.prototype.walk.
When asking for bob.walk you'll get the Person.prototype.walk function because walk could not be found on bob. Asking for ben.walk however will get you the value 22 because the member walk has been created on ben and since JavaScript found walk on ben it will not look in the Person.prototype.
So assignment of a member would cause JavaScript to not look it up in the prototype chain and assign value to that. Instead it would assign the value to an already existing member of the object instance or create it and then assign he value to it.
The next part (More about prototype) will explain this with sample code and demonstrate how to inherit.