2012-11-11

Daddy, what does the "new" keyword do?


Sit down, and I'll tell you. Ok, it creates a new context object for you, then you'll have a new this to work with. This object will be the return value of the expression starting with new. For example,
> function Dog() { this.name = "poo" }
undefined
> new Dog().name
'poo'
But daddy, what happens if you accidentally forget to use new?
Um, er, lemme see.
> Dog().name
TypeError: Cannot read property 'name' of undefined
So, your constructor gets called, but nothing is returned and your Dog is undefined.
But what happened to the name?
Well, it's the name of the Window or what ever your "global object" is, depending on your execution environment. But its bed time now, good night.
< one hour passes >
Dad! I can't get no sleep! What if I return something from my Dog constructor?
< starts node.js >
Well, if you call it with new, the return value is discarded. If you forget the new, the expression evaluates to the return value.
But dad, that makes no sense and can cause unexpected application errors at runtime!!
That's right, son. That's why daddy avoids the new and this keywords. Now good night.

7 comments:

  1. Cool story. Do you have any idea why does node.js handle the return value of constructors in such a non-standard way? Is this a bug or some weird design decision? V8 in Chrome does the right thing and the new Dog returns the return value of the constructor instead, if it's an object.

    ReplyDelete
  2. You are bit wrong with new() and return object. In case you return non-primitive type from constructor object, it would be returned instead of newly created object.

    Check this out,

    http://stackoverflow.com/questions/6750880/javascript-how-does-new-work-internally

    ReplyDelete
  3. That's even crazier, man :) Glad you shared it, though.

    Quite unbelievable that the type of the returned object affects whether it's actually returned or discarded. Someone must have been smoking more than cigarettes.

    ReplyDelete
  4. Why "new"? Because it reads better. I know that when I see `new Object()` I know it is an instance of that object. Otherwise I'd wonder WTF is going on when I just `Object()`?!?? The argument to modify your coding style and avoid language because you might one day forget to include it is a bit strange to me. In the 20 years of programming JavaScript I have never ran across the "is this a function or an object? Opps I meant to construct a new object but forgot the new!" To me it's pretty clear the thought process between "create new object" vs "call a function". And it reads so much better. It also DRYs up the code.

    I beg all developers to fully understand prototypical inheritance before deciding to avoid language features such as "new" and "this".

    ReplyDelete
  5. Returning an object from a constructor function is call [parasitic inheritance][1]. A trick I use quite a bit in Titanium.

    [1]: http://daniel.carrera.name/2008/02/parasitic-inheritance-in-javascript/

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. (edited)

    Thanks for you insights, Sukima. I've learned quite a bit of Javascript after writing this post and now understand the various ways to use or not to use the `new` keyword.

    I still don't like `new` or `this` much more than at the time of writing though. One problem with `new` is that if you write a constructor in the traditional (prototypal inheritance) manner, you cannot use the constructor function like a "normal" function. For instance, you cannot do stuff like

    dogNames.map(Dog)

    In functional programming, this is a real limitation. To me it seems that constructor functions should be first-class functions and not some special things that you must somehow know not to call without `new`. Yet you can still call them without `new` and you'll get crazy results. I still think it's a big poop in programming language design.

    Parasitic inheritance, though, is cool. It's something I've been doing already but it's good to have a name for the pattern. With parasitic inheritance, you don't really need `new` or `this` at all.

    ReplyDelete