tags:

views:

8010

answers:

10

In another question, a user pointed out that the new keyword was dangerous to use and proposed a solution to object creation that did not use new... I didn't believe that was true, mostly because I've used Prototype, Scriptaculous and other excellent JavaScript libraries, and everyone of them used the new keyword...

In spite of that, yesterday I was watching Douglas Crockford's talk at YUI theater and he said the exactly same thing, that he didn't use the new keyword anymore in his code.

Is it 'bad' to use the new keyword? what are the advantages and disadvantages of using it?

+7  A: 

The rationale behind not using the new keyword, is simple:

By not using it at all, you avoid the pitfall that comes with accidentally omitting it. The construction pattern that YUI uses, is an example of how you can avoid the new keyword altogether"

var foo = function () {
    var pub= { };
    return pub;
}
var bar = foo();

Alternatively you could so this:

function foo() { }
var bar = new foo();

But by doing so you run risk of someone forgetting to use the new keyword, and the this operator being all fubar. AFAIK there is no agvantage to doing this (other than you are used to it).

At The End Of The Day: It's about being defensive. Can you use the new statement? Yes. Does it make your code more dangerous? Yes.

If you have ever written C++, it's akin to setting pointers to NULL after you delete them.

Greg Dean
are those two pieces of code EXACTLY equivalent?
Pablo Fernandez
No. With "new foo()" some properties are set on the returned object, like constructor.
some
It's the same, I just omitted any initialization for brevity.
Greg Dean
So, just to make this clear: you shouldn’t use “new” because you might forget it? You are kidding, right?
Bombe
@Bombe : in other languages forgetting "new" would result in an error. In Javascript, it just keeps on trucking. You can forget, and never realise. And simply looking at erroroneous code *wont* be obvious at all whats going wrong.
Kent Fredric
@Greg: I don't see how the first technique allows for use of prototype chains - object literals are great, but throwing away the performance and other advantages provided by prototypes out of fear seems a bit silly.
Shog9
@Bombe - You should use "new" because you (and anyone that uses your code) will never make a mistake? You are kidding, right?
Greg Dean
@Shog - Great point, +1 for the John Resig link too
Greg Dean
Thanks Greg, I think I know why I intuitively took side *for* new when I saw this question. I'm always *offensive*. The glass is half full, whatever those engineers say.
PEZ
+41  A: 

I have just read some parts of his Crockfords book "Javascript: The Good Parts". I get the feeling that he considers everything that ever has bitten him as harmful:

About switch fall through:

I never allow switch cases to fall through to the next case. I once found a bug in my code caused by an unintended fall through immediately after having made a vigorous speech about why fall through was sometimes useful. (page 97, ISBN 978-0-596-51774-8)

About ++ and --

The ++ (increment) and -- (decrement) operators have been known to contribute to bad code by encouraging exessive trickiness. They are second only to faulty architecture in enabling viruses and other security menaces. (page 122)

About new:

If you forget to include the new prefix when calling a constructor function, then this will not be bound to the new object. Sadly, this will be bound to the global object, so instead of augmenting your new object, you will be clobbering global variables. That is really bad. There is no compile warning, and there is no runtime warning. (page 49)

There are more, but I hope you get the picture.

My answer to your question: No, it's not harmful. but if you forget to use it when you should you could have some problems. If you are developing in a good environment you notice that.

some
I completely agree. The solution: Always document how users have to instantiate your objects. Use an example and users will likely cut/paste. There are constructs/features in every language that can be misused resulting in unusual/unexpected behavior. It doesn't make them harmful.
nicerobot
There is a convention to always start constructors with an upper case letter, and all other functions with a lower case letter.
some
I just realized that Crockford don't consider WHILE harmful... I don't know how many time I have created an infinitive loop because I have forgot to increment a variable...
some
Given two equivalent ways of doing something, you'd choose the more dangerous method, just because you can?
Greg Dean
@Greg Dean: That was not was I said. I don't think new is harmful nor continue, ++, --, ==, != and labels on for, while and switch.
some
The question isn't whether or not new is harmful. It's about its disadvantages/advantages. There is one significant disadvantage, in that construction patterns that rely on it, can be harmful, when new is omitted.
Greg Dean
1 advantage as PEZ points out is that is is potentially more clear and familar
Greg Dean
Same goes for ++, --. They express exactly what I intend in the clearest possible language. I love'em! switch fall throughs might be clear to some, but I'm weary about those. I use them when they are clearly more clear ('cuse the pun, couldn't resist).
PEZ
@PEZ: Couldn't resist, could you! ;)
some
My answer to Crockford: Programming is hard, lets go shopping. Sheesh!
Jason Jackson
Very well said sir, very well said. Crockford's sky-is-falling approach isn't helping JS any.
annakata
I haven't read his book. But I think you should learn from your mistakes. If ++ bites him then avoiding ++ **could** be right, for him. Of course, I'm all for Toyotas "five whys" so I would probably dig deeper and find why it **really** bit me.
PEZ
From page 112: "The increment and decrement operators make it possible to write in an extremely terse style. In languages such as C, they made it possible to write one-liners that could do string copies:" (cont...)
some
for(p = src, q= dest; !*p; p++, q++) *q=*p; "They also encourage a programming style that, as it turns out, is reckless. Most of the buffer overrun bugs that created terrible security vulnerabilities were due to code like this."
some
I disagree with some parts of what Crockfords says, and agrees with some other parts, like eval.
some
http://stackoverflow.com/questions/197769/when-is-javascripts-eval-not-evil
Shog9
Thanks. I of course understand that *some* uses of eval are for the good.
PEZ
Yeah. I liked the accepted answer there, good to keep in mind when discussing "evil" features... ;-)
Shog9
@Shog9: I concur
some
"It is a poor workman who blames his tools"
Steven A. Lowe
+7  A: 

I think "new" adds clarity to the code. And clarity is worth everything. Good to know there are pitfalls, but avoiding them by avoiding clarity doesn't seem like the way for me.

PEZ
+20  A: 

Javascript being dynamic language there a zillion ways to mess up where another language would stop you.

Avoiding a fundamental language feature such as new on the basis that you might mess up is a bit like removing your shiny new shoes before walking through a minefield just in case you might get your shoes muddy.

I use a convention where function names begin with a lower case letter and 'functions' that are actually class definitions begin with a upper case letter. The result is a really quite compelling visual clue that the 'syntax' is wrong:-

var o = MyClass();  // this is clearly wrong.

On top of this good naming habits help. After all functions do things and therefore there should be a verb in its name whereas classes represent objects and are nouns and adjectives with no verb.

var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.

Its interesting how SO's syntax colouring has interpretted the code above.

AnthonyWJones
Yeah, I was just thinking the same thing about the syntax coloring.
BobbyShaftoe
Word, Anthony. Word.
PEZ
+4  A: 

I agree with pez and some here.

It seems obvious to me that "new" is self descriptive object creation, where the YUI pattern Greg Dean describes is completely obscured.

The possibility someone could write var bar = foo; or var bar = baz(); where baz isn't an object creating method seems far more dangerous.

annakata
+92  A: 

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:

  1. Prototype inheritance. While often looked at with a mix of suspicion and derision by those accustom 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.
  2. 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 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. 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.)

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).

Shog9
if (!(this instanceof arguments.callee)) throw Error("Constructor called as a function");// More generic, don't require knowledge of the constructors name, make the user fix the code.
some
@some: Yes! If you're able to test and correct client code, then that would be an excellent choice.
Shog9
@Shog9, thanks - excellent comment (learned something new)!
orip
Shog could you edit the answer and give some detail about the advantages of 'new' you mention (speed and full use of prototypes)? I believe this is the most correct answer and I'd mark it as accepted answer if only that things were explained a bit more. Thanks :)
Pablo Fernandez
@Pablo - done. That said, i'm not sure you should accept an answer here; of course, that's up to you, but it seems like a bit of a subjective discussion.
Shog9
The question was if it was 'bad' to use the new keyword, and the advantages and disadvantages of it. I believe your answer explains this in a very complete and concise way. I'm accepting it.
Pablo Fernandez
@Pablo, Shog9: I think it is an excellent answer. Good work,
some
Fantastic answer.
dasil003
Regarding the check, couldn't you assume the global object is window, and do if (this == window) throw ..
meandmycode
@meandmycode: you *could* assume that. But then it would break if `window` *wasn't* the global object for some reason... or if `this` referenced some other context. Also, it's a bit distracting for an example, since the point of the test (whether implicit or explicit) is to verify that the context object is an instance of the constructor function itself.
Shog9
The only reason for this is that arguments.callee is an 'expensive' call to make. I wonder if there are better ways to do this check more generically.. also I think initializing on something other than the global object is more intentional than erroneous.
meandmycode
If you're worried about performance - and actually have reason to be - then don't do the check at all. Either remember to use `new`, or use a wrapper function to remember it for you. I *suspect* that if you're at the point where it matters, you've already exhausted other optimizations such as memoization, so your creation calls will be localized anyway...
Shog9
Sure, I understand the point regarding premature optimizations, it takes a lot of iterations to show the significant expense, '100,000 'function calls just breaks 1ms, when using callee that becomes 304ms.. whilst impresively expensive, its probably completely out of context with the body of the call, and how many times the call actually happens over a given period.
meandmycode
More than happy to bump this to +50 - rational arguments, clean fix to the "problem" everything you want in an answer here
annakata
@some Shouldn't that, ironically, be "new Error"?
bzlm
@bzlm: interestingly, it doesn't actually matter - both `Error()` and `new Error()` return an instance of `Error`. However, given the context... it is funny.
Shog9
@bzlm: LOL! Never saw that one comming! However: ECMA-262, 5th edition, 15.11.1 The Error Constructor Called as a Function:When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. Thus the function call Error(...) is equivalent to the object creation expression new Error(...) with the same arguments.
some
+8  A: 

Another case for new is what I call Pooh Coding. Winnie the Pooh follows his tummy. I say go with the language you are using, not against it.

Chances are that the maintainers of the language will optimize the language for the idioms they try to encourage. If they put a new keyword into the language they probably think it makes sense to be clear when creating a new instance.

Code written following the language's intentions will increase in efficiency with each release. And code avoiding the key constructs of the language will suffer with time.

EDIT: And this goes well beyond performance. I can't count the times I've heard (or said) "why the hell did they do that?" when finding strange looking code. It often turns out that at the time when the code was written there was some "good" reason for it. Following the Tao of the language is your best insurance for not having your code ridiculed some years from now.

PEZ
+1 for the Pooh Coding link - now i need to find excuses to work this into my conversations...
Shog9
LOL! I have years of experience in that particular field and I can assure you that you'll find no difficulties. They often call me Pooh over at robowiki.net. =)
PEZ
Don't know if you'll ever see this comment, but that Pooh Coding link is dead.
Calvin
Thanks for the heads up. We migrated robowiki.net to a new wiki last week and the old content is unreachable at the moment. I'll hurry up with making those old links work.
PEZ
Excellent! Thanks for the new (to me) terminology. I've explained this to people a number of times but never in only 2 words.
pluckyglen
+9  A: 

I am newbie to Javascript so maybe I am just not too experienced in providing a good view point to this. Yet I want to share my view on this "new" thing.

I have come from the C# world where using the keyword "new" is so natural that it is the factory design pattern that looks weired to me.

When I first code in Javascript, I don't realize that there is the "new" keyword and code like the one in YUI pattern and it doesn't take me long to run into disaster. I lose track of what a particular line is supposed to be doing when looking back the code I've written. More chaotic is that my mind can't really transit between object instances boundaries when I am "dry-running" the code.

Then, I found the "new" keyword which to me, it "separate" things. With the new keyword, it creates things. Without the new keyword, I know I won't confuse it with creating things unless the function I am invoking gives me strong clues of that.

For instance, with var bar=foo(); I have no clues as what bar could possibly be.... Is it a return value or is it a newly created object? But with var bar = new foo(); I know for sure bar is an object.

Conrad
+1 and welcome to SO!
some
Agreed, and I believe the factory pattern should follow a naming convention like makeFoo()
pluckyglen
+1 - the presence of 'new' gives a clearer statement of intent.
belugabob
A: 

I think new is evil, not because if you forget to use it by mistake it might cause problems but because it screws up the inheritance chain, making the language tougher to understand.

JavaScript is prototype-based object-oriented. Hence every object MUST be created from another object like so var newObj=Object.create(oldObj). Here oldObj is called the prototype of newObj (hence "prototype-based"). This implies that if a property is not found in newObj then it will be searched in oldObj. newObj by default will thus be an empty object but due to its prototype chain it appears to have all the values of oldObj.

On the other hand if you do var newObj=new oldObj(), the prototype of newObj is oldObj.prototype, which is unnecessarily difficult to understand.

The trick is to use

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

It is inside this function and only here that new should be used. After this simply use the Object.create() method. The method resolves the prototype problem.

Mihir Gogate
To be honest, I'm not wild about this technique - it doesn't add anything new, and as your answer illustrates it can even end up being a crutch. IMHO, understanding prototype chains and object instantiation is crucial to understanding JavaScript... But if it makes you uncomfortable to use them directly, then using a helper function to take care of some details is fine, so long as you remember what you're doing. FWIW: a (somewhat more useful) variation on this is part of the ECMAScript 5th ed. std, and already available in some browsers - **so you should be careful not to blindly redefine it!**
Shog9
BTW: I'm not sure why you made this CW, but if you want to re-post it with the formatting corrections I made, be careful to avoid that checkbox...
Shog9
A: 

I never use the new-keyword. To me 'new' has just been squeezed into the language to make it look more like Java (at the time that was a great marketing move). I consider the new-keyword not really JS. Javascript to me is about objects not classes. New is clearly an indication that there is something similar like a class somewhere - which is confusing and therefore unclear. If you want clearity, dont use 'new', it's not JavaScript, it's a salesman at Netscape interfering with the dev-team.

Gabor de Mooij