user911625
user911625

Reputation:

OO Javascript: use of prototype and call

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

Answers (3)

HMR
HMR

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

Felix Kling
Felix Kling

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

Joe F
Joe F

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

Related Questions