Sunday, November 16, 2014

JavaScript Inheritance Using Call & Apply

Call is a function you can use when you need to invoke one object's methods on another object and also define the scope with the this argument. One way you could do this without using call is through composition. In the following example, cat will execute dog's speak function through composition.

var Dog = function() {
    this.name = "Doge";
    this.speak = function(thing) {
        console.log(this.name + " says " + thing);
    };
};

var Cat = function() {
    this.name = "Kate";

    var dog = new Dog();
    this.speak = function(thing) {
        dog.speak(thing);
    }
};

var dog = new Dog();
dog.speak("bark"); // Prints "Doge says bark"

var cat = new Cat();
cat.speak("meow"); // Prints "Doge says meow"

The problem with the above example is that whether you're calling dog or cat's speak method, the scope is always dog so this.name always returns "Doge". So let's solve this problem with JavaScript's built in call method.

var Dog = function() {
    this.name = "Doge";
    this.speak = function(thing) {
        console.log(this.name + " says " + thing);
    };
};

var Cat = function() {
    this.name = "Kate";
};

var dog = new Dog();
dog.speak("bark"); // Prints "Doge says bark"

var cat = new Cat();
dog.speak.call(cat, "meow"); // Prints "Kate says meow"

And there you have it. Like I mentioned at the beginning of the article, you're able to pass in the scope (this or in this example, our instance of cat). There is another function that's a variation of call and it allows you to pass in an array of arguments instead of explicitly defining each. For example: dog.speak.apply(cat, ["meow"]); This is especially useful when you have a function that accepts a variable number of arguments. Before we wrap up, we'll explain how to use apply towards inheritance by executing the method inside the constructor.

var Animal = function(name) {
    this.name = name;
    this.speak = function(thing) {
        console.log(this.name + " says " + thing);
    };
    this.walk = function() {
        console.log(this.name + " is walking");
    };
};

var Bird = function(name, type) {
    Animal.call(this, name);
    this.type = type;
    this.fly = function() {
        console.log(this.name + " is flying");
    };
};

var bird = new Bird("Dick Grayson", "Robin");
bird.speak("Holy Smokes, Batman!"); // Prints "Dick Grayson says Holy Smokes, Batman!"

So in the above example, you have Bird executing Animal's constructor. Bird also takes the additional argument type, but it doesn't need to be passed to Animal. Finally, within the scope of Bird, we define a new function fly, which is only specific to the Bird subclass.

No comments:

Post a Comment