简体   繁体   中英

Is there something wrong with this approach to Javascript Inheritance?

I am looking to do some inheritance with JavaScript and while searching the inter-webs I found many examples and multiple ways and implementations of inheritance. I eventually found one that I liked because of it's simplicity and from all the reading and learning I came up with this approach:

var Animal = function () {
    var self = this;
    self.legs = 4;
    self.makeNoise = function () {
        return "noise";
    };
};

var Dog = function () {
    var self = new Animal();
    self.base = {
        makeNoise: self.makeNoise
    };

    self.makeNoise = function () {
        var noise = "bark \n";
        noise += self.base.makeNoise();

        return noise;
    };

    return self;
};

var Monkey = function () {
    var self = new Animal();
    self.base = {
        makeNoise: self.makeNoise
    };
    self.legs = 2;
    self.makeNoise = function () {
        var noise = "weird monkey sound \n";
        noise += self.base.makeNoise();

        return noise;
    };

    return self;
};

$("#monkey").click(function () {
    var monkey = new Monkey();
    var result = "Legs: " + monkey.legs + "\n";
    result += "Noise: " + monkey.makeNoise();
    alert(result);
});

$("#dog").click(function () {
    var dog = new Dog();
    var result = "Legs: " + dog.legs + "\n";
    result += "Noise: " + dog.makeNoise();
    alert(result);
});

You can find a working JSFiddle here .

As you can see from the code, I keep a reference of the original base function in a base variable so I can then call base . Do you see anything wrong with this approach? Any shortcomings, overseen issues that might arise in the future, anything I'm missing?

Well, here's one thing that's wrong:

var dog = new Dog();
console.log(dog instanceof Dog) //=> false

The problem is, what you're doing is actually not inheritance. You are simply using functions to return a modified version of the animal object. This results in a behavior which is similar to inheritance but isn't the same thing.

JavaScript's object model uses something called the prototype chain, which is very similar to typical object oriented inheritance. The Mozilla Developer Network has a great article on this: Inheritance and the prototype chain .

Here is an example of how you might use prototypical inheritance in your example:

var Animal = function() {};
Animal.prototype = {
    legs: 4,
    makeNoise: function () {
        return "noise";
    }
};

var Dog = function () {};
// Notice: Dog.prototype is inheriting from Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.makeNoise = function () {
    var noise = "bark \n";
    // Notice: calling Animal's makeNoise function with
    // 'this' set to our dog object.
    noise += Animal.prototype.makeNoise.call(this);

    return noise;
};

var Monkey = function () {};
// Notice: Monkey.prototype is inheriting from Animal.prototype
Monkey.prototype = Object.create(Animal.prototype)
Monkey.prototype.legs = 2;
Monkey.prototype.makeNoise = function () {
    var noise = "weird monkey sound \n";
    // Notice: calling Animal's makeNoise function with
    // 'this' set to our monkey object.
    noise += Animal.prototype.makeNoise.call(this);

    return noise;
};

$("#monkey").click(function () {
    var monkey = new Monkey();
    var result = "Legs: " + monkey.legs + "\n";
    result += "Noise: " + monkey.makeNoise();
    alert(result);
});

$("#dog").click(function () {
    var dog = new Dog();
    var result = "Legs: " + dog.legs + "\n";
    result += "Noise: " + dog.makeNoise();
    alert(result);
});

$("#inheritance").click(function () {
    var dog = new Dog();
    var monkey = new Monkey();
    var result = 'dog instanceof Dog = ' + (dog instanceof Dog) + "\n" +
        'dog instanceof Animal = ' + (dog instanceof Animal) + "\n" +
        'dog instanceof Monkey = ' + (dog instanceof Monkey) + "\n" +
        'monkey instanceof Monkey = ' + (monkey instanceof Monkey) + "\n" +
        'monkey instanceof Animal = ' + (monkey instanceof Animal) + "\n" +
        'monkey instanceof Dog = ' + (monkey instanceof Dog) + "\n";
    alert(result);
});

View JS Fiddle

Besides that by returning self breaks the inheritance chain, you may have a misunderstanding with JavaScript's inheritance technique:

JavaScript is a prototypal-based language, meaning proper inheritance is set up as so:

function Animal(){}

Animal.prototype.walk = function(){
    console.log('walking...');
};

Animal.prototype.roar = function(){
    alert('roar');
};

function Dog(){}

Dog.prototype = new Animal();

Dog.prototype.roar = function(){
    alert('bark!');
};

var animal = new Animal();
var dog = new Dog();

animal.walk();
dog.walk();   // both can call the walk function

animal.roar(); // alerts roar
dog.roar(); // alerts bark

Prototypal inheritance allows shared memory of the object definition (log an object to your console to see what I mean). In other words, every instance of Dog is going to use that same roar function, but by attaching attributes directly to this in the constructor, you're preventing the prototype chain and delegating the memory for the function to every instance of that object. If you're going to create many instances of that object, the performance of the app will reflect this.

@Thom is demonstrating classical inheritance vs. prototypal as in my examples. Either is right, but here is a good Stack answer about this .

This is an excellent article: http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/

//Constructor/Object
function Animal(inNoise) {
    this.legs = 4;
    this.noise = inNoise;
}

//Set Objects prototypes
Animal.prototype = {
    constructor: Animal,
    changeNoise: function(newNoise){this.noise = newNoise;}
}

//Create some dogs
var dog = new Animal('bark');
var pitbull = Object.create(dog);
var chiahua = Object.create(dog);

//Change dogs noise
chiahua.changeNoise('littleBark');

alert(dog.noise); //bark
alert(pitbull.noise);//bark
alert(chiahua.noise); //littlebark
alert(chiahua.legs); //4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM