1

I've recently discovered the whole debate regarding new vs. Object.create(). Coming from doing a ton of OO with new I've learned certain patterns of how to solve my problems. With the intent of learning something different I thought I'd rewrite some simple "classical OO" code to the Object.create() style.

I've run into the problem of nested objects, e.g.

new

   
function Base() {
  this.name = { first: '', last: '' };
}

var a = new Base();
var b = new Base();

a.name.first = 'Sally';
a.name.last = 'Broker';

b.name.first = 'Peter';
b.name.last = 'Davis';

document.write('first:', a.name.first, " last:", a.name.last);  // Outputs { first: 'Sally', last: 'Broker' }
document.write("<br>");
document.write('first:', b.name.first, " last:", b.name.last);  // Outputs { first: 'Peter', last: 'Davis' }

Object.create()

var base = {
  name: {
    first: '',
    last: ''
  }
};

var a = Object.create(base);
var b = Object.create(base);

a.name.first = 'Sally';
a.name.last = 'Broker';

b.name.first = 'Peter';
b.name.last = 'Davis';

document.write('first:', a.name.first, " last:", a.name.last);  // Outputs { first: 'Sally', last: 'Broker' }
document.write("<br>");
document.write('first:', b.name.first, " last:", b.name.last);  // Outputs { first: 'Peter', last: 'Davis' }

I understand why the assignments to the nested objects don't work the same, and also that my thinking is based on coding patterns used in "classical OO". I'm trying to learn how I'm supposed think, design wise, when attacking something where I'd have gone for nested objects, but in terms of best practices for Object.create().

marcusstenbeck
  • 735
  • 6
  • 15
  • 2
    It's worth mentioning that `new` is usually faster and produces better stack traces than Object.create since there is no way to name objects created with a literal as far as I know for the debuggers. – Benjamin Gruenbaum Jan 08 '15 at 15:21
  • I hope that you knew about prototypal inheritance already – thefourtheye Jan 08 '15 at 15:21
  • `Object.create` sets the _prototype_ which you're not really doing anything with this case here. There is _nothing meaningful_ on Base instances' prototypes. – Benjamin Gruenbaum Jan 08 '15 at 15:22
  • @BenjaminGruenbaum This is mostly a personal exercise in furthering my understanding of JavaScript, but I appreciate your comments on why to choose `new`. Thanks. – marcusstenbeck Jan 09 '15 at 10:19

1 Answers1

3

The two versions are not equivalent. In the new case, you're putting that "name" attribute directly on the constructed instance. When you use Object.create() like that, you're not doing so - you're expecting "name" to be inherited from the prototype. Subsequent assignments to properties of the "name" object therefore affect the shared prototype version. (Both a.name and b.name refer to the exact same object, in other words.)

To make a roughly-equivalent version of the new scenario with Object.create() you'd do something like this:

var a = Object.create(Object.prototype, {
  name: {
    value: { first: "John", last: "Doe" },
    writable: true,
    enumerable: true
  }
});

Or, more simply:

var a = Object.create(Object.prototype);
a.name = { first: "John", last: "Doe" };
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Yes, I understand the part where I'm referencing the shared prototype version. However, my question revolves more around how I'd should think differently when coding. Right now it's super easy to just throw together a class with properties containing objects that in turn have properties. With prototypal inheritance I need to re-think the approach. Could you show how you would do it differently? (or am I asking a question that doesn't make sense?) – marcusstenbeck Jan 08 '15 at 15:30
  • @marcusstenbeck well it's really a different question; there's nothing about the difference between `new` and `Object.create()` that affects the way prototypal inheritance works; the mechanism is identical in both cases. In your first `new` example there's no inheritance going on at all (aside from the implicit inheritance from the Object prototype). – Pointy Jan 08 '15 at 15:32
  • Thanks for updating and adding context. The process of creating a new object containing the first and last name is a bit tedious when doing a lot, so … would a factory function usually contain the initialization code? – marcusstenbeck Jan 08 '15 at 15:35
  • I updated the question to reflect that I wasn't really looking for inheritance, but more along the lines of classical OO vs … I don't know what to call it. – marcusstenbeck Jan 08 '15 at 15:38
  • @marcusstenbeck well the first thing to understand is that you really *can't* do "classical" inheritance in JavaScript. You can do things that mimic that behavior in some ways, but the underlying JavaScript mechanisms are fundamentally different. All you've got is prototypal inheritance. If you look around there are zillions of books, blog posts and tutorials on the topic of JavaScript inheritance. – Pointy Jan 08 '15 at 15:45
  • I guess my question really had more to do with the patterns for initializing values in a similar way as a constructor would. However, in the way I worded the question you've actually answered it, so I'll accept your answer. – marcusstenbeck Jan 08 '15 at 15:49
  • @marcusstenbeck ah, OK. Well that'd be a good question too :) – Pointy Jan 08 '15 at 15:51
  • I took a new shot at trying to ask that question here: http://stackoverflow.com/questions/27858568/coding-patterns-for-initializing-objects-constructors-new-vs-object-create – marcusstenbeck Jan 09 '15 at 19:25