2

I'm implementing functions in javascript that inherit from a parent class. It works perfectly with this style of code.

function Foo(){}

Foo.prototype = {
    constructor: Foo,
    name: 'foo',
    tostring: function()
    {
        return this.name;
    }
};

function Bar(){}

Bar.prototype = new Foo();
Bar.prototype.name = 'bar';

var b = new Bar();
console.log(b.tostring());    // says 'bar'

This is okay. But I have a lot of properties in Bar and I don't want to repeat Bar.prototype.someProp every time so I used the shorthand version and it isn't inheriting.

function Bar(){}
Bar.prototype = new Foo();
Bar.prototype = {
    constructor: Bar,
    name: 'bar'
};

console.log(b.tostring());   // doesn't work since the method doesn't exist

I'm assuming Bar.prototype is being overwritten by the native Object of Javascript. How can I inherit using the shorthand Bar.prototype = {} and avoid repetition?

Hawk
  • 167
  • 2
  • 12
  • Why are you modifying the prototype instead of just defining functions on the object? – David Jul 19 '15 at 14:03
  • 2
    Kindly elaborate, @David – Hawk Jul 19 '15 at 14:06
  • See here: http://google.github.io/styleguide/javascriptguide.xml?showone=Method_and_property_definitions#Method_and_property_definitions For debugging purposes, and the safety of the language, it is best to not touch the prototype of an object usually. – David Jul 19 '15 at 14:09
  • @david: that doesn't make sense for custom "classes". – Felix Kling Jul 19 '15 at 14:13
  • @David "The safety of the language" is FUD. Why not use language features if they are there? Just don't change `Object.prototype` itself (the Object class, not individual objects), because it can break wrongly programmed for/in loops. Changing prototypes itself is fine. – thomasfuchs Jul 19 '15 at 14:15
  • Maybe the following answer can help. People already pointed out you re assign prototype after you inherit, you should mutate it instead. And it's best not to create an instance of parent to use as prototype of child, use Object.create instead: http://stackoverflow.com/a/16063711/1641941 – HMR Jul 20 '15 at 05:35

1 Answers1

2

If you use…

Bar.prototype = {
  constructor: Bar,
  name: 'bar'
};

…you're overwriting everything in the Bar prototype, replacing it with a new object. Try setting Bar.prototype.constructor = xxx and Bar.prototype.name = 'bar' individually.

You could define a helper function to reduce repetition but it's probably not worth it if you only need it once:

function extend_with(obj, kv) {
    for (var k in kv) {
        obj[k] = kv[k];
    }
}

extend_with(Bar.prototype, {
    constructor: Bar,
    name: 'bar'
});
melpomene
  • 84,125
  • 8
  • 85
  • 148
thomasfuchs
  • 5,386
  • 2
  • 18
  • 38
  • If i use it individually, there will be too much repetition which I'd like to avoid. – Hawk Jul 19 '15 at 14:05
  • 1
    It doesn't matter—you can't just set the prototype directly with an object, it will overwrite everything that's already in the prototype. There's helper functions in some JavaScript libraries that individually copy properties (e.g. Object.extend in Prototype.js). ECMAScript 6 will have `Object.assign` for this purpose: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – thomasfuchs Jul 19 '15 at 14:06
  • @thomasfuchs Sorry, I just added another variant to your answer. Does it look reasonable to you? – melpomene Jul 19 '15 at 14:11
  • @melpomene: yeah, that's basically what `Object.assign` does (in a simplified way) :) – thomasfuchs Jul 19 '15 at 14:12
  • @thomasfuchs: in es6 one would use `class` I think :) – Felix Kling Jul 19 '15 at 14:14
  • 1
    @FelixKling Fwiw, if you write code that is backwards-compatible, you can (somewhat) easily polyfill `Object.assign`, whereas you won't be able to emulate ES6 classes. – thomasfuchs Jul 19 '15 at 14:16
  • That's true, I didn't think if that. I'm using transpilers in most of my projects that I don't even think about backwards compatibility. – Felix Kling Jul 19 '15 at 14:17