Pergunta

I have a Javascript Object:

var Dog = function() {
    this.speak = function() {
        return 'woof'
    }
    this.trick = function() {
        return 'sitting' 
    }
}

I want to make a new object, Cat, that is based on Dog but has a different speak method:

var Cat = ???
    ...
    this.speak = function() {
        return 'meow'
    }
    ...

So I can ultimately do this:

var tabby = new Cat();

tabby.speak() //returns 'meow'
tabby.trick() //returns 'sitting'

I have little experience with 'object-oriented Javascript' and can't seem to find an example online that reflects what I want to do, nor do I know what keywords to search for.

I thought it would be something similar to how I override functions in Backbone, but this seems different:

var Cat = Dog.extend({
    //the speak function below would override the one that returns 'woof'
    speak: function() {
        return 'meow'
    }
});

Any help is appreciated!

(Above is the simplified version of my ultimate goal - I want to override the render method inside of Rickshaw.Graph.Axis.X)

Foi útil?

Solução

Usually in JavaScript, we'll define methods on a prototype, instead on the instance:

function Dog() {}
Dog.prototype.speak = function () {
    return 'woof';
};
Dog.prototype.trick = function () {
    return 'sitting';
};

The difference between defining a method on a prototype and on the instance is that prototypes allow you to share properties between all objects that have their prototype set to the same object. This object is where you define what properties are shared, and a prototype object can also have its own prototype, creating a prototype chain.

To create a simple example, let's take a look at a simple example:

var foo = { bar: 1 };

// create a new object with its prototype set to `foo`
var baz = Object.create(foo);

console.log(foo.bar); // 1
console.log(baz.bar); // 1

// prototype properties and values are shared
foo.bar = 2;

console.log(foo.bar); // 2
console.log(baz.bar); // 2

// this is an instance property, so the property is no longer shared
baz.bar = 3; 

console.log(foo.bar); // 2
console.log(baz.bar); // 3

If you have a prototypal-inheritance system in place, this is what you'd do:

function Dog() {}
Dog.prototype.speak = function () {
    return 'woof';
};
Dog.prototype.trick = function () {
    return 'sitting';
};

function Cat() {}
Cat.prototype = Object.create(Dog.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.speak = function () {
    return 'meow';
};

Remember that if you define a property on an instance, it will override the property set on the prototype, the prototype's prototype, and so on.


If you're looking for an answer to your specific situation where you have the methods defined on an instance (and it isn't a built-in constructor -- some have special behaviour), you need to do something a bit different:

function Cat() {
    Dog.call(this);
    this.speak = function () {
        return 'meow';
    };
}

What this does is it gives the Dog function the current object of the instance of Cat, on which it can set properties on. This is done by setting the value of this in Dog to the instance of Cat, just for that call using func.call(/* value of this */);.

Outras dicas

Given your current approach, you could do this:

var Dog = function() {
    this.speak = function() {
        return 'woof'
    }
    this.trick = function() {
        return 'sitting' 
    }
}

var Cat = function() {
    Dog.call(this)

    this.speak = function() {
        return 'meow'
    }
}

Though we're not using prototypal inheritance here. We're just assigning own properties directly to the objects. This is less efficient than using shared, inherited methods. Not to mention that the Cat creates the speak method on the Dog, then overwrites it immediately.

var tabby = new Cat();

tabby.speak() //returns 'meow'
tabby.trick() //returns 'sitting'
function Dog() {}

Dog.prototype.speak = function() {
  return 'woof';
};

Dog.prototype.trick = function() {
  return 'sitting';
};

function Cat(){}

Cat.prototype = Object.create(Dog.prototype);

Cat.prototype.speak = function() {
  return 'meow';
};

var fluffy = new Cat();

fluffy.speak(); // 'meow'
fluffy.trick(); // 'sitting'

Basically, you want to do some Googling for "prototypal inheritance".

Same concept as the other answers but here is the javascript secret inherits function slightly simplified from google closure - https://code.google.com/p/closure-library/source/browse/closure/goog/base.js#1578

 var inherits = function(child, parent) {
    function tmp () {};
    tmp.prototype = parent.prototype;
    child.superClass_ = parent.prototype;
    child.prototype = new tmp;
    child.prototype.constructor = child;
  };

Now you can

var Dog = function() {};
Dog.prototype.speak = function(){
    return 'woof';
}
Dog.prototype.trick = function(){
  return 'sitting';   
}

var Cat = function(){};
inherits(Cat, Dog); //weird
Cat.prototype.speak = function(){
        return "meow";
};


var HouseCat = function(){};
inherits(HouseCat, Cat);
HouseCat.prototype.speak = function(){
   return "purr";
};


var dog = new Dog();
var cat = new Cat();
var houseCat = new HouseCat();


console.log(dog.speak());  //woof
console.log(cat.speak());  //meow
console.log(houseCat.speak());  //purr
console.log(houseCat.trick());  //sitting
console.log(cat instanceof Dog);  //true
console.log(houseCat instanceof Cat);  //true
console.log(houseCat instanceof Dog);  //true
console.log(dog instanceof Cat);  //false
console.log(cat instanceof HouseCat);  //false    
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top