Note that there are some explanatory texts on larger screens.

plurals
  1. PORemoving the need for "new"
    primarykey
    data
    text
    <p>A nasty gotcha in javascript is forgetting to call <code>new</code> on a function meant to be instantiated, leading to <code>this</code> being bound to a different object (usually the global) instead of a fresh one. One workaround I read about is to check for it explicitly in the function-constructor using the following idiom:</p> <pre><code>function SomeConstructor(x, y, ...) { // check if `this` is created with new if ( !(this instanceof arguments.callee) ) return new SomeConstructor(x, y, ...); // normal initialization code follows </code></pre> <p>Now <code>new SomeConstructor(...)</code> and <code>SomeConstructor(...)</code> are equivalent.</p> <p>I'd like to simplify this by creating a wrapper function <code>factory(fn)</code> that does the first two lines and then delegates to the wrapped function <code>fn</code>. This would be used like:</p> <pre><code>SomeConstructor = factory(function (x, y, ...) { // normal initialization code follows }) </code></pre> <p>My first attempt was:</p> <pre><code>function factory(fn) { return function() { if ( !(this instanceof arguments.callee) ) { return new arguments.callee.apply(this, arguments); } fn.apply(this, arguments); } } </code></pre> <p>but it fails with "Function.prototype.apply called on incompatible [object Object]". The second attempt was:</p> <pre><code>function factory(fn) { return function() { if ( !(this instanceof arguments.callee) ) { var tmp = new arguments.callee(); arguments.callee.apply(tmp, arguments); return tmp; } fn.apply(this, arguments); } } </code></pre> <p>This sort of works but it may call the wrapped function twice: once with no arguments (to create a new instance) and once with the passed arguments for the actual initialization. Apparently this is fragile and inefficient but I can't figure out a way to do it with a single call. Is this possible ?</p> <p>EDIT: Based on bobince's approach, here's a similar one that does the trick:</p> <pre><code>function factory(init) { var run_init = true; function constr() { if ( !(this instanceof constr) ) { run_init = false; var tmp = new constr(); run_init = true; init.apply(tmp, arguments); return tmp; } if (run_init) init.apply(this, arguments); } return constr; } </code></pre> <p>As for whether this is something that should be encouraged or not, that's debatable. I come from a Python background and I think of <code>new</code> as just noise (Java) or wart (Javascript), but I may be missing something.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload