1

I want to create two functional classes in Javascript: Animal and Zebra. The client script is to instantiate Zebra, and Zebra should then be able to see and call functions from Animal:

Zebra : Animal

Thus, I tried the following, where I use the jQuery $.extend() to make Animal a base class to Zebra:

Animal = function() {
    function hi_animal() {
        console.log('But I am also an animal');
    }

    return {
        hi_animal: hi_animal
    }
}

Zebra = function() {
    $.extend(this, Animal);

    function hi_zebra() {
        console.log('I am a zebra!');

        hi_animal();
    }

    return {
        hi_zebra: hi_zebra
    }
}

$(document).ready(function() {
   var my_zebra = new Zebra();
   my_zebra.hi_zebra();
});

The browser log should show these two lines:

I am a zebra
But I am also an animal

However, I only see:

I am a zebra!
Uncaught ReferenceError: hi_animal is not defined

Here is a fiddle.

What am I missing?

2 Answers 2

3

Your syntax for class inheritance in JS is incorrect. $.extend is intended to transpose object properties. Any effects it has on functions/classes is purely coincidental.

You should define the base classes and then prototype the derived instances. Try this:

function Animal() {
  // put constructor logic here...
}
Animal.prototype.hi_animal = function() {
  console.log('But I am also an animal');
}

Zebra.prototype = new Animal();
Zebra.prototype.constructor = Zebra; // otherwise constructor will be Animal()
function Zebra() {
  // put constructor logic here...
}
Zebra.prototype.hi_zebra = function() {
  console.log('I am a zebra!');
  this.hi_animal();
}

$(document).ready(function() {
  var my_zebra = new Zebra();
  my_zebra.hi_zebra();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Sign up to request clarification or add additional context in comments.

Comments

3

@Rory McCrossan answer is totally correct. But one thing I love about Javascript is how the prototype system works. The below is a slightly modified version of Rory's, but without using the prototype chain, this could have a performance advantage as it keeps the prototype chain more flat. In the world of C# / Delphi etc, it's like you can manipulate the VMT.

function Animal() {
  // put constructor logic here...
}
Animal.prototype.hi_animal = function() {
  console.log('But I am also an animal');
}

function Zebra() {
  // put constructor logic here...
}
Zebra.prototype.hi_zebra = function() {
  console.log('I am a zebra!');
  this.hi_animal();
}
Zebra.prototype.hi_animal = Animal.prototype.hi_animal;

$(document).ready(function() {
  var my_zebra = new Zebra();
  my_zebra.hi_zebra();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

5 Comments

Good alternative. I left mine verbose so it was hopefully a little more obvious to the OP what was happening.
Just to make sure I understand, this is lighter in that situation, but the more functions you add to Animal.prototype, the more unwieldy it becomes right? Because you have to repeat Zebra.prototype.hi_animal = Animal.prototype.hi_animal; for each of them?
@Cristol.GdM Indeed, but then you create functions to apply them. eg. I might have a function called makeControl, makeWindow, makeDraggable, you can then even have a sort of multiple inheritance, makeDraggableWindow = makeWindow + makeDraggable. makeDraggableControl = makeControl + makeDraggable. etc.
@Keith I'm mostly worried about situations where you have the Animal function, with a dozen function, and then a dozen Animal "classes" (Zebra.prototype, Tiger.prototype, etc). If, every time you add new functions to Animal, you have to manually add them to each of its children, looks like it could quickly become an exponential nightmare
@Cristol.GdM No you add it to makeAnimal.. :) I've come from C#/Delphi world, and if you say look at the Object / inheritance tree for controls, it used to be massive, 20 + levels deep. Here you have total control on how you create your VMT, but also keep it flat. Because if the Javascript engine has to traverse 20 + levels deep down the prototype chain, there are performance penalties for this. Because I came from C#/Delphi it took me a while to get away from rigid inheritance, javascript's strength is been dynamic, and much more fun for it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.