0

In javascript, I have an object literal:

var objA = {
  doStuff: function() {
    // do objA stuff
  }
}

I extend objA, and override the doStuff method:

var objB = _.extend(objA, {
  doStuff: function() {
    // do objB stuff
  }
});

However, now when objB.doStuff() is called only objB stuff gets done.

I would like for both objA and objB stuff to be done. I tried the following:

var objB = _.extend(objA, {
  doStuff: function() {
    this.prototype.doStuff.call(this, arguments);
    // do objB stuff
  }
});
objB.__proto__ = objA;

However this doesn't work. I guess I don't understand how prototypal inheritance works when extending object literals. So, what is the right way to do this?

user1031947
  • 6,294
  • 16
  • 55
  • 88
  • For a plain object, its `[[Prototype]]` is *Object.prototype*, so that's where you need to put inherited methods. Note that it's considered bad form to modify the built–in *Object.prototype* object, you should create your own constructor and modify its *prototype*. – RobG Oct 10 '14 at 00:10
  • What do you mean by "*only objB stuff gets done*"? Notice that in your example `objB === objA`! – Bergi Oct 10 '14 at 00:30
  • @Bergi OP is expecting `objB.doStuff()` to also call the "parent method" on `objA`, which of course makes no sense, because `_.extend` doesn't touch prototypes, nor does JavaScript have `super` (yet). – Evan Davis Oct 10 '14 at 00:32
  • You're treating a plain `object` like a `class`. It does not, and should not, work the way you're asking. – Evan Davis Oct 10 '14 at 00:34
  • 1
    You may be interested in patterns for inheritance and overriding: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Oct 10 '14 at 02:16

3 Answers3

1

Unserscore's _.extend function doesn't return a new object.

It returns the same object extended, with the new properties. So, your objA has the new doStuff function.

Instead, you may want to use _.clone and then rewrite doStuff on objB.

Yoann
  • 3,020
  • 1
  • 24
  • 34
1

I would like for both objA and objB stuff to be done.

You have to call the method of objA explicitly:

var objB = _.extend({}, objA, {
  doStuff: function() {
    objA.doStuff.apply(this, arguments);
    // do objB stuff
  }
}, objA);

Note that I'm adding an empty object as first argument, so that first objA's properties are merged and then yours. For more info about how _.extend works, see the documentation.

Object Literals and Prototypal Inheritance?

Object literals currently don't provide a way to set the prototype. You can create an empty object with a specific prototype with Object.create and then merge other properties into it:

var objB = Object.create(objA);
// `merge` is a fictional function that copies properties from object to another
merge(objB, {
   doStuff: function() { ... }
});

You can still only call objA's method by explicitly referencing it.


Note: This section probably has to be revised after ES6 is finalized and implement.

In ES6 you will probably be able to set the prototype via the __proto__ property name:

var objB = {
  __proto__: objA,
  doStuff: function() { }
};

or via Object.setPrototypeOf:

var objB = {...};
Object.setPrototypeOf(objB, objA);

Then you should be able to call objAs method via the super keyword:

var objB = {
  __proto__: objA,
  doStuff: function() {
    super.doStuff();
  }
};
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
0

What you are doing in your example isn't actually inheritance, but simply creation and modification. To achieve inheritance in Javascript, it's not actually an OBJECT that you are extending, per se. It's a function. An object doesn't provide direct access to its prototype, a function does. So what you're after is likely something more like:

function ObjA() {
    return this;
}
ObjA.prototype.doStuff = function() {
    // do objA stuff
};

function ObjB() {
    return this;
}
ObjB.prototype = new ObjA();
ObjB.prototype.doStuff = function() {
    ObjA.prototype.doStuff.apply(this, arguments);
    // do objB stuff
}

var objA = new ObjA(),
    objB = new ObjB();
Christopher
  • 404
  • 2
  • 9
  • 1
    *"An object has no prototype"* Of course it does, every object has a prototype (well, `Object.prototype` doesn't). Don't confuse this with the `prototype` properties of a function. – Felix Kling Oct 10 '14 at 00:27
  • Yes, I believe my wording here is misleading. Just because an object doesn't provide direct access to the prototype by which it was created, doesn't mean that it isn't there. – Christopher Oct 10 '14 at 00:30
  • Yep, every object has an internal `[[Prototype]]` property. You can get the prototype via `Object.getPrototypeOf`. – Felix Kling Oct 10 '14 at 00:31