3

I receive a bunch of objects via JSON which ultimately need to have some instance member functions.

Is there a way to do this without copying the data?

For example:

var DataObject = function() {};
DataObject.prototype.add = function() { return this.a + this.b; };

var obj = JSON.parse('{"a":1, "b":2}');

// Do something to obj to make it inherit from DataObject

console.assert( obj.add() === 3 );

I've tried setting obj.prototype = DataObject.prototype but that doesn't seem to work. What am I missing?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742

1 Answers1

3

Well, in ECMAScript6 (in IE11, and every other non ie browser today), that would be __proto__

obj.__proto__ = Object.create(DataObject.prototype);

[fiddle]

Generally, make sure you only do this at the object creation case, otherwise it can be very risky to do.

Also note, setting the protoype explicitly is not always faster than copying two properties, as you can see here so you have to be sure there is actual gain here.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 1
    (Alternatively, there is an `Object.setPrototypeOf` notation which is supported in less places so I did not mention it in the answer) – Benjamin Gruenbaum Jun 04 '14 at 10:25
  • Question, do you really need Object.create, can't you just reference the DataObjects prototype directly ? – adeneo Jun 04 '14 at 10:27
  • @adeneo from what I understand - yes, had OP asked about making it directly a `DataObject` rather than _inherit_ from `DataObject`, assigning it directly to `DataObject.prototype` would indeed have been a better solution. – Benjamin Gruenbaum Jun 04 '14 at 10:29
  • What difference is there between inheriting from `DataObject` versus being a direct implementation? I just need the functions to exist, however I am mindful of memory and performance in this application. Working in older IE (maybe IE9+) would be good. Would you add anything to your answer in light of this? – Drew Noakes Jun 04 '14 at 10:36
  • @DrewNoakes in all honesty I would either monkey patch the functions to the object after `JSON.parse`ing it (since it would not introduce a closure anyway, the cost would not be very significant), or set the elements on the object explicitly (that is, first parse the JSON and then construct the object explicitly). That said, I'm a traditional guy and in this brave new world this `__proto__` use case might be acceptable. There is no way to make it work (fast) in older versions of IE. Is the extra copy actually a performance bottleneck in your application? – Benjamin Gruenbaum Jun 04 '14 at 10:38
  • My scenario is that I need signalling on arbitrary objects (think something like a `notify` and `subscribe` function) so they don't actually know about or need access to the JSON data members. I'm developing the API now so am not clear whether that's all I need, but you've given me some good ideas to get started with. It may be easiest to just set the functions I need directly on the object, but I wanted to learn something about prototypes and inheritance as I suspected this was a good use case. – Drew Noakes Jun 04 '14 at 10:42
  • Oh, then check NodeJS's `EventEmitter` (there is a port to the browser), that's exactly what it does (generally, that's what event emitters do), check out the pattern of how to apply it. I'd do something differently though, if you just want to make an event emitter, I would definitely just stick a `notify` and `subscribe` function on it. That's called a "mixin" or a "trait" (depending on the language, and more recently a "protocol extension" on swift). It's a great technique in programming and a really powerful one too. – Benjamin Gruenbaum Jun 04 '14 at 10:46
  • 2
    You really should omit the `Object.create` in `__proto__` assignments. OP has surely meant "make `obj` inherit from `DataObject.prototype`", the intermediate object is superfluous. – Bergi Jun 04 '14 at 11:16