3

I have a question for you

As I know, new operator works this way

function fakeNew(Ctor) {
  var instance = Object.create(Ctor.prototype);
  instance.constructor();
  // I skip the conditional for simplicity
  return instance;
}

It all begin when I did a Object.create polifill so I could create objects without using new.

Object.create = function(proto) {
  function F() { }
  F.prototype = proto;
  return new F();
}

I started creating a lot of objcts and prototiping them, but as many times then need to initializa its properties I did a .init() method to them

var base = {
  init: function() {
    EmitterMixin.call(this);
    return this;
  }
};

var obj = Object.create(base).init();

But of course, I had to rembember to return this always from .init() and many times I forget it or worst, I forgot to call .init(). So trying to simplify object initialization I wanted to create a global helper to do it: invoke Object.create, invoke the initializer function and return this.

function create(proto) {
  var child = Object.create(proto);
  child.init();
  return child;
}

Then was when I wanted to hit my head against the wall when I realized what I was doing was virtually what new operator does but a lot slower. And in case the polifill applies I would even use new under the hood.

So I ask myself, what benefits throwing new? It's notably quicker on main browsers and because of javascript nature we usually need to call a initualizer function, something than new does from it's begining.

And worst, I've noticed than I used two different types of objects, "abstract" and "instances", the bigger difference is than for instances I had to invoke .init() while with abstracts it was not necesasary because they will only be used to be prototypes of other objects. And I've already seen this pattern while using new:

function Foo() { }
Foo.prototype.method = function() { ... };

function Bar() { }
// "abstract" doesnt invoke initializer
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.other = function() { ... };

// "instance", the constructor is called as initializer
var obj = new Bar();

Is there really a benefit if we stop seeing new? are we sure it's not a higher-level tool than simplifies something we'll have to do anyway? What pros/cons do you see about new and Object.create?

A. Matías Quezada
  • 1,886
  • 17
  • 34
  • Main [arguments against `new`](http://stackoverflow.com/questions/383402/is-javascript-s-new-keyword-considered-harmful) are "does (lots of) harm when forgotten" and "reminds one too much of class-based inheritance" – Bergi May 06 '13 at 17:38

1 Answers1

1

I have tried both approaches and I don't personally see any problem with the traditional approach using new. The main argument for Object.create is that it makes the prototypal inheritance more clear - you don't have to understand the intricacy of the prototype property on function constructors and how that relates to the actual prototype of the object. But it does require that initialization be a separate step.

My preferred approach is to combine the two approaches, e.g.:

function Animal(name) {
    this.name = name || null;
}
Animal.prototype.eat = function() {
    console.log('yum');
}

function Cat(name) {
    Animal.call(this, name);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.meow = function() {
    console.log('meow');
}

var garfield = new Cat('garfield');
garfield.eat();
garfield.meow();

Object.create is better for inheritance here than Cat.prototype = new Animal() for two reasons:

  1. If you wanted to require the name parameter (throwing an exception if it wasn't passed), you could do so and the inheritance (Cat.prototype = Object.create(Animal.prototype)) would still work.
  2. If you forgot to call the Cat constructor from the Animal constructor, all of the properties that would have been created by the Animal constructor will be undefined instead, allowing you to quickly realize the mistake.

Although this approach (using constructor functions and new) is less "purely" prototypal, it's still prototypal inheritance and as long as you understand how to use it correctly it works just fine, and requires a little less typing than the Object.create approach.

I wrote some other notes about this in the documentation for my Javascript OO library, simpleoo. (Note: I may be changing the API soon for that library; I'm linking to it mainly because the documentation discusses some of these concepts in more detail.)

Matt Browne
  • 12,169
  • 4
  • 59
  • 75