BanksySan
BanksySan

Reputation: 28500

Can't access methods on object's prototype

I can create a Cat object and set a method on it's prototype to print out the cat's name.

var log = function(message) {
  var results = $('#result');
  results.append('<p>' + message + '</p>');
};

function Cat(name) {
  this.name = name;
}

Cat.prototype.speak = function() {
  log('My name is ' + this.name);
};

var fluffy = new Cat('Fluffy');
var tiddles = new Cat('Tiddles');

log(fluffy.name);
fluffy.speak();
log(tiddles.name);
tiddles.speak();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>

However, when I try to set the cat's prototype to an animal, I can't access the speak method:

function Animal(name, sound) {
    this.name = name;
    this.sound = sound;

    this.speak = function() {
        log(sound + '! My name is ' + name);
    };
}

function Cat(name) {
    this.prototype = new Animal(name, 'Meow');
}

var fluffy = new Cat('Fluffy');

fluffy.speak();  // TypeError: undefined is not a function

Why does fluffy not get the speak() method of its prototype?

Upvotes: 4

Views: 7023

Answers (2)

Oriol
Oriol

Reputation: 288080

The problem is that you set speak as a privileged method inside Animal constructor.

However, that constructor is never called for Cat instances.

Moreover, you can't use prototype property to modify internal [[prototipe]] and change the object from which properties should be inherited. You can use non standard __proto__ or ECMAScript6 Object.setProtetipeOf, but better don't do that.

Instead, better use this approach:

function SuperClass(args) {
    // Here add SuperClass privileged properties
}

// Here add public properties to SuperClass.prototype

function SubClass(otherArgs) {
    // Add SuperClass privileged properties to SubClass instances:
    SuperClass.call(this, args);

    // Here add SubClass privileged properties
}

// Make SubClass instances inherit from SuperClass.prototype:
SubClass.prototype = Object.create(SuperClass.prototype);

// Fix constructor property, overriden in the line above
SubClass.prototype.constructor = SubClass;

// Here add public properties to SubClass.prototype

function log(message) {
  document.body.innerHTML += '<p>' + message + '</p>';
}

function Animal(name, sound) {
  this.name = name;
  this.sound = sound;
}

Animal.prototype.speak = function() {
  log(this.sound + '! My name is ' + this.name);
};

function Cat(name) {
  Animal.call(this, name, 'Meow');
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

var fluffy = new Cat('Fluffy');

fluffy.speak();

Upvotes: 2

Felix Kling
Felix Kling

Reputation: 816364

If you want to learn how to do inheritance in JS, please read this guide . prototype is a property of the constructor function, not the instance.

Why does fluffy not get the speak() method of its prototype?

Because it's not on its prototype. You are never mutating Cat.prototype. The way you set up Animal, you would have to call Animal inside Cat instead:

function Cat(name) {
    Animal.call(this, name, 'Meow');
}

But if you want proper prototype inheritance, define speak on Animal.prototype and set up inheritance via Object.create:

function Animal(name, sound) {
    this.name = name;
    this.sound = sound;
}

Animal.prototype.speak = function() {
    log(this.sound + '! My name is ' + this.name);
};

function Cat(name) {
    Animal.call(this, name, 'Meow');
}
Cat.prototype = Object.create(Animal.prototype);

Upvotes: 9

Related Questions