58

Crockford's book, JavaScript: The Good Parts, says (on page 114) that constructor functions should always be given names with an initial capital letter (ie. Point), and that function names with initial capital letters should only be used with constructor functions (everything else should be lowerCase).

This convention helps us avoid forgetting to use the new operator with constructor functions.

He goes on to say that "[a]n even better coping strategy is to not use new at all."

My question is, how do we program JavaScript without using new at all?

  • We can avoid new Object() and new Array() with the literal {} and [].
  • We can avoid new Number(), new Boolean(), and new String() with 0, true and ''.
  • We can avoid new RegExp() with something like /pattern/.

How do we avoid new Date()?

And, most importantly, how do we avoid using new with our own custom Objects?

Kevin Brown-Silva
  • 40,873
  • 40
  • 203
  • 237
Rudiger
  • 581
  • 1
  • 5
  • 3
  • 1
    Prototyping, prototyping, prototyping. – Oded Mar 07 '11 at 19:36
  • What argument does he have? I have a complete project relying on `new` for a great deal and it has helped alot in organising it. – pimvdb Mar 07 '11 at 19:38
  • 2
    have a look at [Can I construct a JavaScript object without using the new keyword](http://stackoverflow.com/questions/1889014/can-i-construct-a-javascript-object-without-using-the-new-keyword) – Maxym Mar 07 '11 at 19:40
  • 3
    I can't for the life of me see why you would want to dismiss such a construct, seemingly at the whim of ones own laziness or to compensate for ones forgetfulness. Intriguing, nonetheless. – Grant Thomas Mar 07 '11 at 19:45
  • 1
    @GrantThomas, IMO, its to compensate for the "stupidity" of programming in a language where it is possible to leave out the word `new`, and not find out until runtime. – ToolmakerSteve Feb 15 '17 at 05:13

9 Answers9

42

Crockford gives an example for an object creation function as should have been provided by JS itself in one of his Javascript talks available on http://developer.yahoo.com/yui/theater/

However, the YUI(3) team itself uses "new", and they DO follow his recommendations (since he's the Yahoo chief JS architect (UPDATE: he moved on, but the statement was true when this response was originally written). I understand this particular statement to be more on an "academic" level, what SHOULD have been HAD the language been designed "right" and not with some leftovers of the class-based inheritance stuff. He (IMHO rightly) says that the way it turned out JS is conflicted, prototype based but with this one thing from "classical class" inheritance languages.

However, JS is as it is so go and use "new".

You can find his object creation function here: http://javascript.crockford.com/prototypal.html

 if (typeof Object.create !== 'function') {
     Object.create = function (o) {
         function F() {}
         F.prototype = o;
         return new F();
     };
 }
 newObject = Object.create(oldObject);


EDIT: Updated to use Crockford's latest version of that function - there are three.


UPDATE June 2015: We have had Object.create(...) for quite a while now, which all current browsers support (incl. IE 9 and above), so there was no need to use Crockford's function.

However, it turns out that if you use Object.create you should make sure that you don't do that a lot: That function is FAR slower than using new Constructor()!

See http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html for an explanation (for the V8 engine), and see http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/62 for a performance demo.

Another reason to not turn your back on new Constructor(...) is that ES6 classes will surely see wide-ranging adoption even if only for the simple reason that most Javascript developers come from class-based languages.

Also check out this article, which argues for Object.create: http://davidwalsh.name/javascript-objects-deconstruction

Like it or not, especially in projects you want to share with a wide range of people (in space and time -- meaning right nor or over time, other people taking over from you) there are more reasons for using new.

UPDATE September 2015: For myself, I have begun to use ES 2015 Javascript for everything - using either io.js and/or Babel. I also don't use any new in my projects except for the Javascript built-ins like new Error(...). I prefer to use the far more powerful functional approach, I completely ignore the object system. [my-object].prototype and this are completely gone from my projects. For the longest time I was VERY skeptical of these ideas "because objects work just fine". But after very reluctantly giving it a try at the beginning of a new (io.js) project it "clicked" and I don't understand why I wasted two decades. Okay, not quite, today the JS engines and hardware are much more conducive to that style. Especially with ES 2015, I recommend giving a functional style entirely free of any this and class (the new ES 2015 keyword or the entire concept, based on using constructorFn.prototype) a try. It may take you a few weeks but once it "clicks" I promise you won't ever go back - not voluntarily. It's so much more convenient and more powerful.

UPDATE February 2018: While I still do what I wrote in the previous update I now want to add that sometimes classes are fine. There are no absolutes. :-)

Mörre
  • 5,699
  • 6
  • 38
  • 63
  • Is there a particular "functional style" here you are referring to? Or just generally applying functional programming philosophy to Javascript to nullify some of these issues? – djfdev Nov 07 '15 at 00:31
  • 1
    @Mörre Noseshine With regards to your update (September 2015), I would really like to see how you achieved this (not using any 'new' or 'this'). Could you provide and example? Do you use a factory function as well as Object.create to do this? Thanks. – mbx-mbx Nov 10 '15 at 09:51
  • 4
    @Magrangs No. I just call functions. The state you store in objects I store in variables of functions - using the (lexical) scoping rules of the language. If the outside needs access to my internal state I hand back an object with (only) methods (that are inside my lexical scope and therefore have access), just an object literal container. It is needed because a function can only have one return value. Lexical scope takes the place of objects. – Mörre Feb 05 '16 at 09:02
  • 1
    Please don't vandalize your posts. – greg-449 Apr 23 '17 at 07:11
  • 1
    I wouldn't call this vandalism but enlightenment –  Oct 22 '17 at 09:44
12

I don't know how to avoid new Date() or new XMLHttpRequest() either. But I do know how to avoid using new for my own types.

First, I start with Object.create(). This is an ES5 method, so it's not available everywhere. I add it using the es5-shim, ad then I'm ready to go.

I like the module pattern, so I start by wrapping my type in a self-executing anonymous function, var Xyz = (function() {...})(). This means I have a private space to work without making a mess in the global namespace. I return an object with a create() function, and a prototype property. the create() function is for users of my type. When they want one, they call Xyz.create(), and get back a new, initialized object of my type. The prototype property is available if people want to inherit.

Here's an example:

var Vehicle = (function(){
        var exports = {};
        exports.prototype = {};
        exports.prototype.init = function() {
                this.mph = 5;
        };
        exports.prototype.go = function() {
                console.log("Going " + this.mph.toString() + " mph.");
        };

        exports.create = function() {
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        };

        return exports;
})();

and inheritance looks like this:

var Car = (function () {
        var exports = {};
        exports.prototype = Object.create(Vehicle.prototype);
        exports.prototype.init = function() {
                Vehicle.prototype.init.apply(this, arguments);
                this.wheels = 4;
        };

        exports.create = function() {
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        };

        return exports; 

})();
Sean McMillan
  • 10,058
  • 6
  • 55
  • 65
11

Not using new and blindly following Crockford is silly.

Understand JavaScript and write good code. Using the new keyword is the Cornerstone of JavaScript OO.

You are going to miss out on a lot of good JavaScript code by avoiding new.

Rather than arbitrarily cutting huge chunks out of your toolkit, learn it and use it properly instead.

Crockford has a habit of saying that anything in JavaScript which ever gave him a bug in his code is bad.

I would personally go on to say that "[a]n even better coping strategy is to be competent."

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 25
    I wouldn't say that `new` is the Cornerstone of JavaScript OO. – Sean McMillan Apr 05 '11 at 03:34
  • How do you make objects without the `new` keyword? – Raynos Apr 05 '11 at 07:01
  • @SeanMcMillan you realise any reference to `{}` is a reference to `new Object()` right? You simply can not create objects without the `new` keyword. – Raynos Apr 05 '11 at 07:13
  • 11
    @Raynos: I beg to differ; while `{}` and `new Object()` have the same result (a new empty object) they exactly in the fact that `{}` does not use the `new` keyword. If you have es5's `Object.create()`, then the only time you will need new is for `Date` and `Error` (in core JS. You will also need it for browser types, but rarely.) You can write substantial, well organized javascript without using `new`. – Sean McMillan Apr 08 '11 at 14:15
  • @SeanMcMillan you are correct `Object.create` is an exception. But I will insist that in essence any reference to `{}` is a simple _macro_ for `new Object()`. The cornerstone of JavaScript OO is the ability to create an object that inherits from a prototype. `new`, `{}` and `Object.create` all achieve this. There's a difference between what `new` means and the literal keyword `new`. The literal keyword is not neccesary but the concept of `new` is. – Raynos Apr 08 '11 at 14:45
  • 4
    @Raynos: Oh sure, absolutely. Concern over `new` in javascript is all about the lack of ability to tell if a function requires `new` or not, and the danger of running a constructor over the global object if you forget the `new`. Poor `new` gets blamed for the brokenness of `this` on global functions. – Sean McMillan Apr 08 '11 at 14:53
  • 1
    @SeanMcMillan I agree that `this` can use some help. I fall for the trap a few times. The main issue is not knowing whether third party code is constructors or not and being used to calling say `jQuery` without `new` even though its a constructor. I would indeed have been better if `new` was attached to function declarations instead of to function calls. The cornerstone I'm referring to is the ability to inherit from a prototype though. I guess maybe `.prototype` would have been a better phrase to "label" it as. – Raynos Apr 08 '11 at 15:03
  • 4
    Erm... you misspelled "competent" :) – fredoverflow Jul 03 '11 at 14:41
  • 8
    @SeanMcMillan so two months later I agree, `new` is horrid, use `Object.create` :) – Raynos Jul 03 '11 at 14:45
  • I'd agree with Crockford when he says that everything which tends to give bugs for many developers is dangerous. It's always better to choose language options which give less chance for bugs, especially because not every developer out there is competent (no matter how you spell it :D ) – JustAMartin Oct 07 '13 at 07:50
  • Crockford is the godfather of javascript. Saying it's silly blindly following him is an unnecessary comment. Everybody should follow his advice as he wrote one of the best books about javascript. Please use Object.create. – hopper Nov 03 '14 at 23:03
6

You can avoid new by creating factory functions:

var today = Date.getToday();

(In case you were wondering, you can't avoid it on the factory function itself:)

Date.getToday = function() { return new Date(); };

Although I only think you should create such functions if it adds semantic value (as in the case above) or if you can default some of the constructor parameters. In other words, don't do it just to avoid using new.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 1
    I think he means that one would do: `Date.prototype.getToday = function() { ... }` – Pointy Mar 07 '11 at 19:43
  • 1
    While that is true it is not what Douglas Crockford meant to say, and this question is about just that. See http://javascript.crockford.com/prototypal.html – Mörre Mar 07 '11 at 19:45
  • @Pointy: No, he meant what he wrote. The point is to be able to write Date.getToday() instead of new Date(). If he declared the function on the prototype, he would have to write new Date().getToday(), thus defeating the point of the exercise. – KaptajnKold Mar 13 '11 at 14:44
  • Oh OK, I see what you guys are doing now. Thanks for the clarification (not that it wasn't clear originally; I was just confused). – Pointy Mar 13 '11 at 15:47
  • 2
    Especially provide factories for your own types. even if you have to use `new`, don't make your clients use it. – Sean McMillan Apr 08 '11 at 14:17
6

This question has already been asked and answered: Is JavaScript's "new" keyword considered harmful?

As Raynos said, blindly following Crockford (or anyone else for that matter) without understanding why they say the things they do, is silly.

Community
  • 1
  • 1
Stephen
  • 18,597
  • 4
  • 32
  • 33
  • Very good point, because in that context Crockford talks about JS's history and in a larger context of where it comes from, and how it SHOULD have been. Since we ended up with JS as it IS we use "new". – Mörre Mar 07 '11 at 19:56
3

I think his advice of not using new at all is conceptual (academic) and not to be taken literally. The Date class is a perfect exception to the rule because how else can you get a current (or arbitrary) date object using standard ECMAScript?

However, regarding not using new with your own custom objects you can use a few strategies. One is to use factory-like methods instead of constructors which could take as an argument an object instance to "bless" into your new type, or use a new object literal by default. Consider the following:

var newCar = function(o) {
  o = o || {};
  // Add methods and properties to "o"...
  return o;
}
maerics
  • 151,642
  • 46
  • 269
  • 291
2

You're stuck with using 'new' to instantiate other people's objects. But for your own code, you can avoid the pitfalls of both 'this' and 'new'.

(By the way, the issue really isn't with 'new' itself. But an object being instantiated with 'new' is probably using 'this' internally. Use of 'this' leads to frequent and subtle bugs, because javascript's 'this' requires the caller to do extra work to bind the called method to the right object, and incorrect bindings are hard to lint or otherwise detect before runtime.)

Short version:

To avoid using 'new' to instantiate objects you write, just return an object from any function. Inside that function, attach any methods to that object and do any initialization. You're done -- that function is both your class definition and constructor.

Long version, with example:

The following 'self' pattern avoids use of both 'new' and 'this'. While the pattern does store method copies in each object, this won't matter unless you're creating a lot of objects at runtime. If that's the case, then you can always use the 'flyweight' pattern from http://justjs.com/posts/this-considered-harmful. (While the examples on that page still use 'this' a little, it's a slight tweak to adapt those to the following pattern as well.)

// this function defines a "class" -- the whole function is the constructor
function Foo(x) {
    // create/init whatever object type you want here
    var self = {x: x};
    // if subclassing, for instance, you can do:
    // var self = Baz(x);

    // public method
    self.foo = function() {
        return self.x;
    };

    // public method
    self.bar = function() {
        console.log(self.x);
        logger();
    };

    // private method
    function logger() {
        console.log(self.x);
    }

    // ...more constructor bits can go here

    // don't forget to return self
    return self;
}

var f = Foo(1); 
var g = Foo(2); 
setTimeout(f.bar, 1000);
setTimeout(g.bar, 1000);

console.log(g.foo()); // 2
g.x = 5;
console.log(f.foo()); // 1
console.log(g.foo()); // 5

// ...then, 1 second later:
// 1  (from f.bar)
// 1  (from f.logger)
// 5  (from g.bar)
// 5  (from g.logger)

// blows up if uncommented
// f.logger();
stevegt
  • 1,644
  • 20
  • 26
1
function F() { return { /* your fields and methods here */ } }
Murali VP
  • 6,198
  • 4
  • 28
  • 36
1

You can avoid "new" by returning an anonymous object and using a closure in your constructor. This also help you hide private data.

Consider:

function SomeCounter(start) {

    var counter = start;

    return {
        getCounter : function() {
            return counter;
        },

        increaseCounter : function() {
            counter++;
        }

    };
}

Now to use this, all you need to do is

var myCounter = SomeCounter(5);
myCounter.increaseCounter();
console.log(myCounter.getCounter()); //should log 6

The beauty of this is that you do not need to remember to use "new", but if you do it won't hurt you.

var myCounter = new SomeCounter(5); //still works
Zaven Nahapetyan
  • 1,259
  • 1
  • 10
  • 15
  • 1
    While this _is_ true, I would be very upset if you are calling functions with `new` that don't need it. And making all of your methods into closures means that you require storage for each method on every instance of your type. – Sean McMillan Apr 05 '11 at 03:39