Reputation:
I have this code:
function Stickman() {
//some methods and properties
}
function JuniorStickman() {
Stickman.call(this);
this.p = new value // override a property in Stickman
}
JuniorStickman.prototype = new Stickman();
junior = new JuniorStickman();
I adapted this code from an example at MDN: https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
What I don't understand is this: call() and the line
JuniorStickman.prototype = new Stickman()
seem to do the same thing. If I comment out the line
JuniorStickman.prototype = new Stickman();
my JuniorStickman still has all the methods and properties of Stickman; True; his prototype property is now JuniorStickman and not Stickman but it doesn't seem to matter.
How does call work here to make my Junior Stickman (junior) have all the methods of Stickman and is the prototype assignment necessary?
As I understand it call() is not really giving me inheritance. I am just getting a sort of copy of Stickman to which I can add / override properties. Is this correct?
Upvotes: 0
Views: 171
Reputation: 39270
JavaScript prototype is like sub classing. But all instances of a "child" objects inherit one parent instance. Complex values that are changed are changed for all children instances.
When using parent.call(thisContext) the parent's variables declared in the parent's function body with this.somevar will become unique to the child's instance because they are initialized to the this context of the child. When you only have the parent.call(this then the child would not be an instance of the parent so:
(child instanceof parent) would be false if you only use parent.call(this
function parent(){
this.arr=[];
this.name="parent";
}
function child1(){
parent.call(this);//sets all this elements
//of parent to the current
// instance of child1
}
child1.prototype = new parent();
function child2(){
}
child2.prototype = new parent();
var c1=new child1();
c1.name="c1"
c1.arr.push(["c1"]);
var anotherc1=new child1();
anotherc1.name="another c1";
anotherc1.arr.push("another c1");
var c2 = new child2();
c2.name="c2";
c2.arr.push(["c2"]);
var anotherc2 = new child2();
anotherc2.name="another c2";
anotherc2.arr.push(["another c2"]);
console.log(c1.name,c1.arr);//["c1"]
console.log(anotherc1.name,anotherc1.arr);//["anotherc1"]
console.log(c2.name,c2.arr);//["c2","anotherc2"]
console.log(anotherc2.name,anotherc2.arr);//["c2","anotherc2"]
console.log(c1 instanceof parent);//true
Upvotes: 0
Reputation: 816422
How does call work here to make my juniorStickman have all the methods of Stickman
Your comment in the code seems to indicate that you are setting all properties (also methods) inside the Stickman
constructor. Therefore, if you call Stickman
and explicitly set this
to the new JuniorStickman
instance (Stickman.call(this);
) all properties that are assigned to this
inside Stickman
are assigned to the new instance.
All that .call
[MDN] does is setting this
inside the function to refer to the first argument. Example:
function foo() {
alert(this.bar);
}
foo.call({bar: 42}); // alerts 42
foo.call({bar: 'baz'}); // alerts baz
So why is .call
used here? It plays the same role as calling super()
in other languages: It executes the parent constructor on the new child instance.
is the prototype assignment necessary
It is not in your case. But usually you assign all properties which should be shared across instances to the prototype of the function, i.e. Stickman.prototype
. Methods for example are typically assigned to the prototype. Only properties that are specific to each instance should be assigned in the constructor.
If you would not do this assignment, an instance of JuniorStickman
would not have any of the methods that are assigned to Stickman.prototype
since it is not in the instance's prototype chain.
FWIW, setting up inheritance by assigning a new instance of the parent to the prototype is not an optimal way. What if Stickman
requires mandatory arguments? Which ones would you pass?
You don't want to create a new Stickman
instance at this moment, all you want is bring Stickman.prototype
into the prototype chain. This can be easily done using Object.create
[MDN]:
JuniorStickman.prototype = Object.create(Stickman.prototype);
Upvotes: 3
Reputation: 652
If your Stickman() constructor does something differently for each new instance (suppose it set a property to be equal to the time when it was created), then you would want each instance of JuniorStickman() to call the Stickman() constructor instead of relying upon the timestamp which would be stored in the prototype from when you called Stickman() to set the prototype.
For example:
function a() {
this.time = new Date().getTime();
}
function b() {
// a.call(this)
this.hello = "something";
}
b.prototype = new a();
With that line commented out, the timestamp of every new b() is the same, but if you un-comment that line then they behave as you would want them to.
Upvotes: 0