JavaScript: Good details - how not to use `new` at all

Crockford's book, JavaScript: “Good Details,” says (on page 114) that constructor functions should always have names with an initial capital letter (that is, a period), and function names with initial capital letters should only be used with a constructor (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 "an 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 letters {} 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?

+56
javascript constructor new-operator oop
Mar 07 '11 at 19:33
source share
9 answers

Crockford gives an example of an object creation function that should have been provided by JS itself in one of its Javascript conversations, available at http://developer.yahoo.com/yui/theater/

However, the YUI (3) team itself uses the “new” one, and they fulfill their recommendations (since he is the chief architect of JS Yahoo (UPDATE: he switched, but the statement was true when this answer was originally written) I understand that this particular statement is more it looks like an “academic” level that SHOULD understand that the language was designed “correctly” and not with some remnants of class-based inheritance.He (IMHO rightly) says that the path turned out to be JS conflicting based on the prototype, but with this one of the classi inheritance languages class. "

However, JS is as it is, and use the "new" one.

Here you can find its object creation function: 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 the latest version of this Crockford feature - there are three.


UPDATE June 2015: we already have Object.create(...) that all current browsers (including IE 9 and above), so there was no need to use the Crockford function.

However, it turns out that if you use Object.create , you must make sure that you do not: this function is slower than when 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 to demonstrate performance.

Another reason not to turn to new Constructor(...) is that ES6 classes will undoubtedly see widespread adoption, even if only for the simple reason that most Javascript developers come from classes.

Also check out this article claiming Object.create : http://davidwalsh.name/javascript-objects-deconstruction

Whether you like it or not, especially in projects that you want to share with a wide range of people (in space and time, which means right or not time, other people charge you) there are more reasons to use new .

UPDATE September 2015: for myself, I started using Javascript ES 2015 for everything - using either io.js and / or Babel. I also do not use any new in my projects, except for built-in Javascript, such as new Error(...) . I prefer to use a much more powerful functional approach, I completely ignore the object system. [my-object].prototype and this completely disappeared from my projects. For a long time I was very skeptical of these ideas "because objects work very well." But after he reluctantly gave him an attempt at the start of a new project (io.js), he “clicked”, and I don’t understand why I spent two decades. Well, not quite, today JS engines and hardware are much more favorable for this style. Especially with ES 2015, I recommend giving a functional style that is completely free of any this and class (the new ES 2015 keyword or the whole concept based on using constructorFn.prototype ). This may take several weeks, but as soon as it “clicks”, I promise that you will never return - not voluntarily. It is much more convenient and powerful.

+39
Mar 07 '11 at 19:40
source share

Not using new and blindly following Crockford is stupid.

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

You are going to miss a lot of good JavaScript code while avoiding new .

Instead of arbitrarily cutting huge pieces from your toolbox, study it and use it correctly.

Crockford has the habit of saying that anything in JavaScript that ever gave him an error in his code is bad.

I personally would like to say that "it is better to use a coping strategy."

+12
Mar 07 '11 at 19:45
source share

I do not know how to avoid new Date() or new XMLHttpRequest() . But I know how to avoid using new ones for my own types.

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

I like the module template, so I start by ending my type in a self- var Xyz = (function() {...})() anonymous function, var Xyz = (function() {...})() . This means that I have a personal space to work without messing up the global namespace. I am returning an object using the create() function and the prototype property. The create() function is for users of my type. When they want, they will call Xyz.create() and return a new, initialized object of my type. The prototype property is available if people want to inherit.

Here is 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 is as follows:

 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; })(); 
+12
Apr 08 2018-11-14T00:
source share

You can avoid new by creating factory functions:

 var today = Date.getToday(); 

(If you are interested, you cannot avoid this in the factory function itself :)

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

Although I think that you should create such functions if it adds a semantic value (as in the case above), or if you can use some constructor parameters by default. In other words, do not do this to avoid using new .

+6
Mar 07 '11 at 19:40
source share

This question has already been asked and answered: Is JavaScript a “new” keyword considered harmful?

As Reynos said, blindly following Crockford (or anyone else for that matter), not understanding why they say what they are doing, is stupid.

+5
Mar 07 2018-11-11T00:
source share

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

However, if you are not using new with your own custom objects, you can use several strategies. One of them is to use factory-like methods instead of constructors that can take an instance of an object as an argument to “bless” 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; } 
+3
Mar 07 2018-11-11T00:
source share
 function F() { return { /* your fields and methods here */ } } 
+1
Mar 07 '11 at 19:44
source share

You can avoid the “new” by returning an anonymous object and using closure in your constructor. It will also help you hide personal data.

Consider:

 function SomeCounter(start) { var counter = start; return { getCounter : function() { return counter; }, increaseCounter : function() { counter++; } }; } 

Now, to use this, you only need

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

The beauty is that you do not need to remember the use of the “new”, but if you do, it will not hurt you.

 var myCounter = new SomeCounter(5); //still works 
+1
Mar 07 '11 at 19:49
source share

You are stuck in using the “new” to create other people's objects. But for your own code, you can avoid the pitfalls of both 'this' and new.

(By the way, the problem is really not the “new.” But the object created with the “new” probably uses 'this' inside. Using 'this' leads to frequent and subtle errors, because javascript 'this' requires that the caller did additional work to bind the called method to the desired object, and incorrect bindings are difficult to use or otherwise detect before execution.)

Short version:

To avoid using the “new” to create the objects you write, simply return the object from any function. Inside this function, attach any methods to this object and do any initialization. You are done - this function is both your class definition and constructor.

Long version, for example:

The following “self” pattern avoids the use of either “new” or “w654”. Although the template stores copies of methods in each object, it does not matter if you do not create many objects at run time. If so, then you can always use the fly template from http://justjs.com/posts/this-considered-harmful . (Although the examples on this page still use 'this' a bit, this is a small tweak to adapt them to the next template.)

 // 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 gx = 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(); 
0
Jul 02 '17 at 23:33
source share



All Articles