Is JavaScript'S "New" Keyword Considered Harmful

Is JavaScript's new keyword considered harmful?

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

Is JavaScript 's “new” Keyword Considered Harmful (Part 2)?

You right, using new is considered harmful as it doesn't place enough emphasis on OO in JavaScript being prototypical. The main issue is that acts too much like classical classes and one should not think about class. One should think about Object's and creating new Objects with existing objects as blueprints.

new is a remnant of the days where JavaScript accepted a Java like syntax for gaining "popularity".

These days we do Prototypical OO with Object.create and use the ES5 shim.

There is no need for new anymore.

Before the days of ES5 being commonly implemented (only FF3.6 and IE8 are slacking) we used new because we had little choice. someFunction.prototype was the way to do prototypical inheritance.

I recently wrote up a "nice" demonstration of Object.create although I still need to iron out some kinks in the usage. The important thing is to separate Objects from factory functions.

Omitting 'new' keyword causing unexplainable problems in javascript constructor function

Value of this depends on how the function is called.

In non-strict mode, when you call the altFruit function without the new keyword, this inside it will refer to the global window object. So,

this.person = person;

will add person property on the global window object. (you can test this by logging window.person on the console at the end of your code).

When you call aFunction, in non-strict mode, value of this inside displayInfo function will refer to the global window object.

In short, your code is adding and reading properties to and from the global window object, respectively.

The "new" operator

new operator is used to create instances of user-defined object types (like Fruit) or built-in object types (like Array, Date, etc).

When you call new Fruit(...), new operator will do the following things:

  1. Create a new object

  2. Add __proto__ property on the newly created object that points to Fruit.prototype object.

  3. Point this inside the Fruit constructor to the newly created object.

  4. Return the newly created object from the Fruit constructor function.

For more details, see: MDN: new operator

JavaScript avoiding new keyword

Alright, let's take the new example:

function Bar() {
var value = 1;
// Whoops, sorry
// As Bergi points out, if you have a return value then that overrides the normal object that is returned by new
// Didn't even notice you have a return in here!
/*
return {
method: function() {
return value;
}
}
*/
// This does the same thing (approximately) but now calling "(new Bar()) instanceof Bar" will be true
this.method = function() {
return value;
};
}
Bar.prototype = {
foo: function() {}
};

var b = new Bar();

In the google chrome console, b has a property called __proto__. Basically, when you call b.foo(), first the browser looks for a method called foo. If it doesn't find it, it looks in b.__proto__ and b.__proto__.__proto__ and so on.

Notice: b.__proto__ === Bar.prototype

That means if you call new Bar() repeatedly, they will all have the same __proto__, which saves memory. (This has the side effect of, if you mutate Bar.prototype, it will change all instances of Bar's __proto__ as well).

Let's look at your factory method:

var Foo = function () {
var foo = function () {

};
foo.prototype = {
bar: function () { }
};
return new foo();
};

This doesn't save memory because it creates a new prototype, and a new constructor every time you call Foo(). So in other words, if

var f1 = new Foo(), f2 = new Foo();

The following return false: f1.constructor == f2.constructor and f1.__proto__ == f2.__proto__. What does this mean? It means that f1 and f2 don't share the same prototype so the objects have to be duplicated every time. Perhaps, you could do this:

var fooProto = {
callFoo: function() { alert("test"); }
};
function Foo() {
var foo = function() {};
foo.prototype = fooProto;
return new foo();
};

This would use the same amount of memory as the regular constructor.

Side edit: Modern browsers have a built-in function that does something like Foo in the last example. You could use Object.create(fooProto) (but only in newer browsers).

Also, note that __proto__ is technically a hidden, read-only property (although some browsers let you write to it). It was only used for the sake of showing what goes on behind the scenes, and it shouldn't be used in real code.

Javascript new keyword usage

Without new, this refers to the global object, and not any object returned from the function.

If you were to execute your code, you'd find that the first hp would be undefined, whereas the second would be [object Object]. Further, for obvious reasons, the first would not have a property of hardDrive or processor, but the second would.

In the first example, your two properties would have been added to the window object.

Why does Crockford say not to use the new keyword if he advises us to use it for prototypal inheritance?

Crockford discusses new and Object.create in this Nov 2008 message to the JSLint.com mailing list. An excerpt:

If you call a constructor function without the new prefix, instead of
creating and initializing a new object, you will be damaging the
global object. There is no compile time warning and no runtime
warning. This is one of the language’s bad parts.

In my practice, I completely avoid use of new.



Related Topics



Leave a reply



Submit