Crockford has done a lot to popularize good JavaScript techniques. His opinionated stance on key elements of the language have sparked many useful discussions. That said, there are far too many people that take each proclamation of "bad" or "harmful" as gospel, refusing to look beyond one man's opinion. It can be a bit frustrating at times.
Use of the functionality provided by the new
keyword has several advantages over building each object from scratch:
- Prototype inheritance. While often looked at with a mix of suspicion and derision by those accustomed to class-based OO languages, JavaScript's native inheritance technique is a simple and surprisingly effective means of code re-use. And the
new
keyword is the canonical (and only available cross-platform) means of using it.
- Performance. This is a side-effect of #1: if I want to add 10 methods to every object I create, I could just write a creation function that manually assigns each method to each new object... Or, I could assign them to the creation function's
prototype
and use new
to stamp out new objects. Not only is this faster (no code needed for each and every method on the prototype), it avoids ballooning each object with separate properties for each method. On slower machines (or especially, slower JS interpreters) when many objects are being created this can mean a significant savings in time and memory.
And yes, new
has one crucial disadvantage, ably described by other answers: if you forget to use it, your code will break without warning. Fortunately, that disadvantage is easily mitigated - simply add a bit of code to the function itself:
function foo()
{
// if user accidentally omits the new keyword, this will
// silently correct the problem...
if ( !(this instanceof foo) )
return new foo();
// constructor logic follows...
}
Now you can have the advantages of new
without having to worry about problems caused by accidentally misuse.
John Resig goes into detail on this technique in his Simple "Class" Instantiation post, as well as including a means of building this behavior into your "classes" by default. Definitely worth a read... as is his upcoming book, Secrets of the JavaScript Ninja, which finds hidden gold in this and many other "harmful" features of the JavaScript language (the chapter on with
is especially enlightening for those of us who initially dismissed this much-maligned feature as a gimmick).
A general-purpose sanity check
You could even add an assertion to the check if the thought of broken code silently working bothers you. Or, as some commented, use the check to introduce a runtime exception:
if ( !(this instanceof arguments.callee) )
throw new Error("Constructor called as a function");
Note that this snippet is able to avoid hard-coding the constructor function name, as unlike the previous example it has no need to actually instantiate the object - therefore, it can be copied into each target function without modification.
ES5 taketh away
As Sean McMillan, stephenbez and jrh noted, the use of arguments.callee
is invalid in ES5's strict mode. So the above pattern will throw an error if you use it in that context.
ES6 and an entirely harmless new
ES6 introduces Classes to JavaScript - no, not in the weird Java-aping way that old-school Crockford did, but in spirit much more like the light-weight way he (and others) later adopted, taking the best parts of prototypal inheritance and baking common patterns into the language itself.
...and part of that includes a safe new
:
class foo
{
constructor()
{
// constructor logic that will ONLY be hit
// if properly constructed via new
}
}
// bad invocation
foo(); // throws,
// Uncaught TypeError: class constructors must be invoked with 'new'
But what if you don't want to use the new sugar? What if you just want to update your perfectly fine old-style prototypal code with the sort of safety checks shown above such that they keep working in strict mode?
Well, as Nick Parsons notes, ES6 provides a handy check for that as well, in the form of new.target
:
function foo()
{
if ( !(new.target) )
throw new Error("Constructor called as a function");
// constructor logic follows...
}
So whichever approach you choose, you can - with a bit of thought and good hygiene - use new
without harm.
new
. But when you look at the YUI library. You have to usenew
everywhere. Such asvar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
. – Avellanedainit
method if you're using theObject.create
approach and call that after. Much easier to just usenew
which does both, sets the prototype chain and calls some initializer code. – Jordisonnew
isn't dangerous. Omittingnew
is dangerous, and therefore bad. But in ES5 you can use Strict Mode, which protects you from that danger and many others. – Westcottthis
won’t beglobalThis
in a function call, but it goes beyond that: classes cannot be used withoutnew
at all. Since ES6, the language has moved on to encourage the use ofnew
, as seen by newer constructors such asMap
orSet
not being usable (anymore) withoutnew
. Going against this doesn’t seem reasonable. Note that old constructors, e.g.new String
,new Date
,new Array
, have old rules. – Modification