I am trying to understand why and when we use constructors in Javascript.
I was wondering when and how we need to use the constructor of a child and when the parents. Based on my tests there is NO difference when I set the child constructor to itself or to the parent.Lets take a look at the below code :
function Mammal(name) {
this.name = "###"+name;
}
Cat.prototype = new Mammal(); // Here's where the inheritance occurs
Cat.prototype.constructor = Cat; // Otherwise instances of Cat would have a
function Cat(name) {
this.name = name;
}
Now lets instantiate the Cat and Mamal class and see the name:
var mycat = new Cat('Felix');
Alert(mycat.name); //OUTPUT : "Felix"
Now i want to set the constructor of Cat class to the Mamal. To do so I remove the below line
//Cat.prototype.constructor = Cat; -->Now the cat Constructor is set to its default(Mamal)
Now I expect that when I call mycat.name, it uses the Mamal constructor and alert "###Felix"
BUT it doesn't. It shows exactly same as the previous result "Felix".
var mycat = new Cat('Felix');
Alert(mycat.name); //Again OUTPUT is : "Felix" !! but I expected "###Felix"
So, why? And can you give me an example of a correct use of constructors in Javascript and when they are important?
Hopefully an examination of how this code runs should clear things up:
function Mammal(name) {
this.name = "###" + name;
}
function Cat(name) {
this.name = name;
}
Cat.prototype = new Mammal();
// omitted change of Cat.prototype.constructor
var felix = new Cat("Felix");
console.log(felix);
After defining the first two functions, we create a new Mammal, passing it a name of undefined, and putting the result into Cat.prototype. Now Cat.prototype is a Mammal with a name of ###undefined.
Then we create a new Cat, giving the Cat function a name of Felix. This Cat function sets its name property to Felix. The Cat function completes and felix contains a Cat object with a name of Felix.
So why didn’t the Mammal function run? Well, it did, but only once when setting up inheritance. If you want the superclass’s constructor to run as part of the subclass’s initialization, you have to do that explicitly:
function Cat(name) {
Mammal.call(this, name);
this.name = name;
}
Of course, you’d still get the same result, because you’d have the Mammal function set the name property and then Cat would write over it again. You could swap it around, too, so the Mammal overwrites what Cat did:
function Cat(name) {
this.name = name;
Mammal.call(this, name);
}
But then the Cat line of this.name = name; is useless and you might as well remove it.
So why didn’t your constructor change do anything? Because that’s not what constructor does. In fact, reading through the ES5 specification, I didn’t see the constructor property actually being used for anything at all. Changing constructor doesn’t do anything, so that’s why it didn’t matter.
Related
How does the new work differently in the 2 examples below? I see that the 2nd example is replacing the annoymous funciton with a variable, but in the second one, the function/class "Person" is actually being called. Does it make any difference if it's being called or not? I tried it without the calling and it still worked. So that led me to believe that new is actually calling the function and setting up this to be assigned to the instance variable.
var person = new function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
person.setName("Rafael");
console.log(person.sayHi()); // Hi, my name is Rafael
var Person = function() {
this.setName = function(name) {
this.name = name;
}
this.sayHi = function() {
return "Hi, my name is " + this.name;
}
}
var personTwo = new Person()
personTwo.setName("Rafael");
console.log(personTwo.sayHi()); // Hi, my name is Rafael
There would be almost no difference between these two examples, if it was a simple function like this:
(function() { console.log("IIFE"); })();
// or
var f = function() { console.log("Function"); };
f();
You just store your function in a variable, and then call it.
However, it makes a little difference, since it is related to JS OOP mechanisms. In the first case you get Object instance, and in the second you get Person instance. This makes difference in OOP sense.
var person = new function() { };
console.log("Is instance of: " + person.constructor.name);
console.log("There is no way to check instanceof in this case");
var Person = function() { };
var person = new Person();
console.log("Is instance of: " + person.constructor.name);
console.log(person instanceof Person);
In general, new and classes are supposed to be used as in the second case in order to enable the full functionality of JS OOP. There is absolutely no sense or/and advantage in using anonymous class constructor.
Whether or not it is assigned into a variable: does not matter. It is completely parallel to this example:
var x = 1;
console.log(x);
and
console.log(1);
Whether it needs to be called or not: A function with the new operator is always being called, but with new, parentheses are optional when no parameters are passed: new Person() is equivalent to new Person, but new Person("Joe") cannot be done differently.
In the second example, you are passing to the new operator the exact same function. You simply are using a reference (logically stored in a variable) instead of writing literal function just in place.
So, your second example is the same as:
var personTwo = new (function() {
[...]
})()
[...]
Which, in fact, is much the same as the first one:
var person = new (function() {
[...]
})
[...]
NOTE that the parentheses surrounding the function are absolutely optional in this case. You could be placed there seven if you like: (((((((function(){[...]}))))))).
The point here is that when you say «in the second one, the function/class "Person" is actually being called» you are WRONG there: That function, which acts as a constructor isn't being called by you. You are simply passing it as a parameter (the constructor function) of the new operator which is, in fact, who is actually calling the constructor with the rest of parameters you provided, if any.
See new syntax documentation:
new constructor[([arguments])]
The constructor is the function you pass to the new operator and the parameters are specified between parentheses. But they are fully optional (including the parentheses itself).
This is why new constructor; without parentheses works.
To be clear: What you thought happens (but not) would be written as:
var person = new ((function(){...})()) ();
...or, more verbosely:
var person = new (
(function(){ // Constructor builder.
[...]
return function(){...}; // Actual constructor.
})() // Constructor builder call
//v-- Parentheses to force builder to be called.
) (); // <-- Parameters (if any) passed to the constructor.
Below is my sample code,
function Employee(name){
this.name = name;
}
Employee.prototype.getName = function(){
return this.name;
}
var a = new Employee("a");
function Manager(name){
this.name = name;
}
var b = new Manager("b");
//Case:1
Manager.__proto__ = Employee.prototype;
console.log(b.getName());
//Case:2
b.__proto__.__proto__ = Employee.prototype;
console.log(b.getName());
Case: 1 When the Manager's dunder proto is pointing to the Employee prototype it produces TypeError(TypeError: b.getName is not a function).
Case: 2 However in this case when the Employee prototype is pointed starting from the Manager's instance dunder proto(i.e. b.__proto__), this would work fine and gives the correct result.
According to the law of inheritance,
1. instance 'b' initially looks for the function getName in itself if it was created through the constructor mode.
2. Else would look for the getName in Manager's prototype object.
3. Now the next level is Object.prototype.
Please correct me if I am wrong in any sense.
But I would wish to point the Manager's __proto__ to Employee prototype instead of Object.prototype.
I tried to achieve this by Manager.__proto__ = Employee.prototype; and b.__proto__.__proto__ = Employee.prototype;. Only the latter worked correctly.
Why did Manager.__proto__ = Employee.prototype; throw TypeError when both the methods are pointing to Employee prototype??
I am reading John Resig's slideshow http://ejohn.org/apps/learn/#78
Its not clear to me why i need to include .prototype in the line Me.prototype = new Person();
function Person(){}
Person.prototype.getName = function(){
return this.name;
};
function Me(){
this.name = "John Resig";
}
Me.prototype = new Person();
var me = new Me();
assert( me.getName(), "A name was set." );
Think of it this way, if every person is going to have a name, it's easier to assign the getName function to it's prototype.
In this case, you have a Person that has a prototype function to get a name, and a few lines below you have a Me function that assigns a name by default. Since we want to incorporate the getName function, we use the Person which already has that function object built-in. When you construct Me() and assign to me you can call getName() and use that to return the name, which by default is "John Resig"
The same thing can be achieved without prototype, like this
function Me(){
this.name = "John Resig";
this.getName = function () {
return this.name;
}
}
var me = new Me();
...BUT by using prototype, it helps create objects a lot faster, you can refer to this answer as well.
To implement inheritance in Javascript, one generally does the following 2 steps;
Say I have a base class "Animal"
var Animal = function(name){
this.name = name;
}
I now want to derive a sub class "Dog" from the same. So I would say
var Dog = function(name) {
Animal.call(this,name);
}
So I am calling my parent class constructor from my derived class constructor.
The 2nd step is to set the prototype as follows;
Dog.prototype = new Animal();
Now I can access any of the base "Animal" class properties from within my derived class Dog.
So my question is why are these 2 steps necessary ?
If we just call the base class constructor using
Animal.call(this,name);
isn't that enough for implementing Inheritance ?
Why do we also need to set the prototype property using Dog.prototype = new Animal(); ?
I wanted to understand what each of the above 2 steps does ?
var Animal = function(name){
this.name = name;
}
Animal.prototype.sleep = function() {
console.log("Sleeping")
}
...
// Without this line:
Dog.prototype = new Animal();
// the following code will fail, since `d` does not contain `sleep`
d = new Dog();
d.sleep();
Animal.call(this,name); simply calls the function Animal, but using the same this as the calling function.
Dog.prototype = new Animal(); sets the prototype of the prototype. However, Dog.prototype = Object.create(Animal.prototype) might be more correct.
A code sample is worth a thousand words :)
var Animal = function(name) {
this.name = name;
}
Animal.prototype.run = function () {
// do something
};
var Dog = function(name) {
Animal.call(this, name);
}
var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "undefined"
dog instanceof Animal; // false
dog instanceof Dog; // true
Dog.prototype = new Animal();
var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "function"
dog instanceof Animal; // true
dog instanceof Dog; // true
As you can see, if you don't use Dog.prototype = new Animal();, Animal.prototype members won't be inherited. Moreover, Dog instances won't be considered as instances of Animal.
The first thing to understand is that in JavaScript there is no classical inheritance, the mechanism we know from C-languages like Java, C# and so fort. In JavaScript, code reuse can be accomplished by using prototypal-inheritance. The only thing we have is objects, blocks of code who are alive and don't need to be instantiated. For example: when a function is invoked on an object - like a method, the current object is inspected whether the function is known. If not found, the engine calls it prototype (which is an other object) and inspects whether the function name is known and can be invoked. When not found, íts prototype is called and so on. So, setting the prototype of a object one can orchestrate the prototype-chain.
To answer your question: nothing is necessary, its up to you what you want. Code reuse is what you want and inheritance is the way you can achieve this (Stoyan Stefanov - JavaScript Patterns). In JavaScript, more ways are available to reuse code.
Furthermore, this is bound to the current context, not always the current object.
There are no classes, nor subclasses, in javascript.
call and apply execute a function in the context of a different 'this'. What you have in your sample code is unneeded.
//Create your constructor function:
var Animal = function(){}
Animal.prototype = {
sleep: function(){
console.log('zzz');
},
bark: function(name){
console.log(name +' barks!');
}
}
var dog = new Animal();
dog.sleep();
dog.bark('asdasd');
Second step helps you to inherit prototype methods. Imagine that we have more complex class:
function Animal(name) {
this.name = name;
}
// shared method
Animal.prototype.say = function () {
alert( this.name );
};
function Dog() {
Animal.apply(this, arguments);
}
Dog.prototype = new Animal();
var dog = new Dog('Cooper');
// method has been inherited
dog.say(); // alerts 'Cooper'
You can try it here
Here we define the constructor function for Animal
var Animal = function(name){
this.name = name;
}
Then define the constructor function for Dog and from inside it we invoke the constructor function of Animal. Just like we do super() in class based object oriented design.
var Dog = function(name) {
Animal.call(this,name);
}
Then we build the prototype of Dog by consuming the methods defined in the prototype of
Animal. Here it does not clone methods in Animal , but a link is set between Dog and Animal using which it re uses the methods in Animal
Dog.prototype = new Animal();
And continue extending it adding more methods
Dog.prototype.showName = function(){
// do something
}
So if I was to create an object literal like this..
var person1 = {
age : 28,
name : 'Pete' }
Then I add a function to the object...
person1.sayHelloName = function(){
return 'Hello ' + this.name;
};
alert(person1.sayHelloName());
Im wondering where the 'prototype' keyword comes into all this. I cant add a prototype to an object (only to a function constructor) so would I be able/have to use the prototype in this scenario.
You can't use the prototype in this way because, like you say, it's used to add properties to a constructor which must be defined with the function() keyword. What you are doing in your example is extending the person1 object, but that object is just a single variable and not an instantiable class. Meaning you can't "create" another person1 using the new keyword, whereas you could if it were an instance of a defined class.
You don't have to (can) use prototype here. As you have only one instance of something (one object), you can set the functions directly on the object.
FWIW, ECMAScript 5 defines Object.getPrototypeOf with which you can get the protoype of any object (only available in "modern" browsers).
var Person = function() {
this.age = 28;
this.name = "peter";
}
Person.prototype.sayHelloName = function(){
return 'Hello ' + this.name;
};
var person1 = new Person;
You would bring prototype into play to define methods all instances of a class have. In your case that doesn't make any sense since you only create a standalone object that doesn't belong to a class.
function Person (age, name)
{
this.age = age;
this.name = name;
}
Person.prototype.sayHelloName = function ()
{
return 'Hello ' + this.name;
}
person1 = new Person(28,'Pete');
alert(person1.sayHelloName());
This only makes sense of course if you are expecting to be creating more than one person.
There's no need for you to use 'prototype' in object literal. Only when you use the constructor pattern (and some other design patterns), that you can use 'prototype'.