4

I mean code like this:

 function MyObject(x, y, z) {
     this.init(x, y, z);
 }
MyObject.prototype = {
    constructor: MyObject,
    init: function(x, y, z) {
        // actually use x, y, z
    },
    other methods
};

Why not just not have an init method and do all the initialization in the constructor?

Jamie
  • 3,901
  • 3
  • 23
  • 27

2 Answers2

0

None. Really, none. Your constructor function does not do anything more than init. This is more or less an antipattern.

The advantage of a method that initializes the object would be that it could be called multiple times (on the same object), for use in object pooling or if just to reset it. However, every well-engineered JS object does have that method already: it's called .constructor(). It's the constructor function, by default available on its own prototype, and usually put on it explicitly if necessary (as was done in your example).

This means having an extra init method is rather useless, typically less performant and more verbose. Except maybe that you use this verbosity to emphasize (by name, and style of declaration) the use of it as a method, and possibly to ease a planned refactoring so that the actual constructor would do more than the init method (e.g. create constant fields). I'd avoid doing this prematurely, though, yagni.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • `init` can be overridden by the object creator and called from `constructor` without having to deal with a `super` implementation (see Backbone models as an example.) This question is WAY too opinion-based to be valid. – Evan Davis Oct 17 '14 at 03:43
  • @Mathletics: Not sure what you mean by "the object creator". But just overwriting the constructor would be possible as well, even if some inheritance frameworks think using `init` methods is simpler. – Bergi Oct 17 '14 at 03:46
  • "object creator" == the author; this is why I try not to post while tired :) – Evan Davis Oct 17 '14 at 03:50
  • @Bergi: Overriding the constructor fails when the parent object keeps state in a closure (private vars). By the time you override the constructor it's too late, you're no longer in the parent constructor's scope. – slebetman Oct 17 '14 at 04:35
  • 1
    @slebetman: I don't understand what you mean by "*you're no longer in the parent constructor's scope*". You can [trivially call the super constructor](http://stackoverflow.com/a/12463270/1048572) to create its private state vars. – Bergi Oct 17 '14 at 04:42
  • Hmm.. didn't consider using call to call the parent constructor. Good point. – slebetman Oct 17 '14 at 04:49
0

In javascript, there is unfortunately no clean way to pass arguments up the constructor chain because constructors inherit from objects, not other constructors. For example consider the following:

function Person (name) {
    this.name = name;
}

function Accountant () {}

Accountant.prototype = new Person('');

Now, if you want to create an Accountant there's no clean way to give him a name:

var x = new Accountant();

Of course, in this simple example you can simply set his name manually after creating him:

x.name = 'Andy';

But real world code may not always be as easily worked-around. Some object keep state in closures which means you'll have no way to pass the argument back to the parent's constructor because you've created the parent object when defining the child object's prototype.

One work-around is of course to not use inheritance at all but use decorator functions as if they were constructors:

function new_person (name) {
    var self = {};
    self.name = name;
    return self;
}

function new_accountant (name) {
    var self = new_person(name);
    return self;
}

This design pattern is often called parasitic inheritance. Notice that in this design pattern we don't use the keyword new.

Another work-around, if you still want to use proper inheritance, is for objects to have an init function that can be called by any constructor that wants to inherit it:

function Person (name) {
    this.init(name);
}

Person.prototype.init = function (name) {
    this.name = name;
}

function Accountant (name) {
    this.init(name);
}

Accountant.prototype = new Person('');

There are other, more fancy work-arounds of course. This being javascript, you're only limited by your creativity. But for prototype inheritance the init function looks like the simplest work-around requiring minimal code without needing additional libraries or a new version of the language.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 1
    What do you consider to be a "*clean way*"? Btw, `Accountant.prototype = new Person('')` [is not proper inheritance](http://stackoverflow.com/q/12592913/1048572)! – Bergi Oct 17 '14 at 04:47