0

JavaScript can create a object in many ways.

I try the following code to avoid new keyword to create a new Object of Class A.

My question is that A.prototype.init() here is whether equals new A()? is this good for practice, and why?

function A(){
}
A.prototype.init=function(){
    return this;
}

var a = A.prototype.init();
console.log(a);

var a1=new A();
console.log(a1);

jsfiddle

caoglish
  • 1,343
  • 3
  • 19
  • 29
  • When you call `A.prototype.init` you're not passing a context; it's not the same. – elclanrs Sep 17 '13 at 02:54
  • 1
    `A.prototype.init() === A.prototype.init()` but `new A() !== new A()`. They are doing different things. – Casey Foster Sep 17 '13 at 02:55
  • I am not sure I completely understand what you're asking. – Sethen Sep 17 '13 at 02:56
  • There is no reasonable cause to [avoid the `new` keyword](http://stackoverflow.com/questions/383402/is-javascript-s-new-keyword-considered-harmful), especially when you have initialisation to do. – Bergi Sep 17 '13 at 03:50

3 Answers3

2

All you're doing is returning the A.prototype object. You're not really initializing anything, and you're not using the result.

console.log(A.prototype === A.prototype.init()); // true

So unless you have a particular use in mind, I'd say, no it's not a good practice.


Not sure exactly why you want to avoid new, but in any case, you can change your constructor so that it can be called with or without new and still behave like a constructor.

function A() {
    var ths = Object.create(A.prototype);

    ths.foo = "bar";

    return ths;
}

Now it won't matter if you use new. You're going to get a new object that inherits from A.prototype no matter what.

You can still use an .init() method, but you might as well just put the logic in the constructor.


Furthermore, you can easily create a factory that takes care of that little bit of boilerplate code.

function Ctor(fn) {
    return function() {
        var ths = Object.create(fn.prototype);
        fn.apply(ths, arguments);
        return ths;
    };
}

So now you'd create your constructor like this:

var A = Ctor(function() {
    this.foo = "bar";
});
user2736012
  • 3,543
  • 16
  • 13
  • you are right,although console.log the 'same text', but one of 'this' is prototype and one is object of A. thanks clear my mind. – caoglish Sep 17 '13 at 03:04
1

You can avoid new by encapsulating your code with the module pattern and returning a function that calls the constructor, in other words:

var A = (function ClassA() {

  // Constructor
  function A(prop) {
    this.prop = prop; // instance property
    this._init();
  }

  // Public methods
  A.prototype = {
    _init: function() {

    }
  };

  // Mini factory to create new instances
  return function(prop) {
    return new A(prop); // well, only one `new`
  };
}());

Now you can create new instances without new:

var a = A('foo'); //=> A { prop: "foo", init: function }
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Ditch the `ClassA` in this code. It adds nothing and arguably confuses and isn't very readable. JSLint will read this as a constructor and throw an error also. Your variable name should really be the name here. – Sethen Sep 17 '13 at 03:04
  • It adds meaning. Ditch JSLint for JSHint. – elclanrs Sep 17 '13 at 03:05
  • It uhh... It really doesn't... And no. – Sethen Sep 17 '13 at 03:06
  • I would even do `init: function init(){}`. Named functions let you trace the stack faster so you can debug without "anonymous function" everywhere. – elclanrs Sep 17 '13 at 03:07
  • To each his own I guess. – Sethen Sep 17 '13 at 03:08
  • ^^ That's my point xD. Some like JSLint some JSHint, some prefer named function expressions others prefer anonymous. I don't use it everywhere though, I do believe it adds meaning here, you're saying: this is a Class (or a module if you will), not a regular function, given that it returns a factory and not a constructor. – elclanrs Sep 17 '13 at 03:10
0

Usually you catch direct function calls with instanceof:

function MyConstructor (a, b, c) {
    if (!(this instanceof MyConstructor)) {
        return new MyConstructor(a, b, c);
    }
    // ...
}

but there is no good reason to avoid using new. Object.create and other alternatives can have a significant performance impact.

Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66