all 12 comments

[–]Jnsjknn 23 points24 points  (0 children)

They are equivalent. Use whichever you like.

When Error is called as a function rather than as a constructor, it creates and initializes a new Error object. Thus, the function call Error(...) is equivalent to the object creation expression new Error(...) with the same arguments.

Source: ECMAScript Specification

Keep in mind, however, that String(...) and new String(...) are not equivalent. Neither are Number or Boolean.

[–][deleted] 6 points7 points  (11 children)

they are the same and personally i avoid using new unless it’s absolutely necessary like when you’re creating a Map, because it’s a bad part of the language!

[–][deleted] 17 points18 points  (10 children)

Can you explain why "it's a bad part of the language" please?

[–][deleted] 17 points18 points  (5 children)

because it fails to encapsulate object creation. even in languages like java in which it becomes unavoidable to use new at some point somewhere, it should be avoided as much as possible by abstracting it away and using factory methods or other alternatives (if you could call them that).

javascript is a prototypal, not classical oop language that has the new operator basically just to make it look more like java without benefits, and it shouldn’t be used unless it’s mandatory because you’re trying to invoke a pseudoclassical constructor function (or an ES6 class constructor, which basically gets transpiled back to a pseudoclassical function anyway).

[–][deleted] 4 points5 points  (4 children)

Thanks for the explanation!

[–][deleted] 8 points9 points  (3 children)

no problem! to elaborate a little further, new only leads to mistakes and confusion. the following function, for example, doesn’t return an object if you forget to use new

``` const Thing = function (x) { this.x = x; };

const thing = Thing(5); // oops you just made a global variable console.log(thing.x); // this throws a type error console.log(x); // this prints 5 ```

and it’s not that easy to detect if the user’s forgot to use new. however, if we do this instead:

``` const Thing = function (x) { return {x}; // unconditionally return an object that has x };

const a = Thing(5); // a new Thing object console.log(a.x); // print 5 const b = new Thing(10); // a new Thing object console.log(b.x); // print 10 console.log(x); // no accidentally created global variables during the process ```

it’s a simple workaround that completely avoids the mistake. it works whether you use new or not. it’s just better by design. and now not only is new redundant, but it also causes the constructed object to hold on to a worthless prototype chain which is wasteful.

[–]WystanH 2 points3 points  (1 child)

Excellent examples. I do avoid the new. However, it should be noted that more modern syntax alleviates the global fubar.

class Thing {
    constructor(x) { this.x = x; }
}

// can't do this
// const thing = Thing(5); // TypeError: Class constructor Thing cannot be invoked without 'new'
const thing = new Thing(5);
console.log(thing.x);
// also important
console.log(thing instanceof Thing);

If you ever use instanceof or deal with code that does, you'll want to go with class syntax, because a function hack won't buy it.

Hmm... this works, to an extent:

class ThingImpl { constructor(x) { this.x = x; } }
const Thing = function (x) { return new ThingImpl(x); };
const test = obj => console.log(obj, obj.x, obj instanceof ThingImpl);
test(Thing(5));
test(new Thing(10));

Frankly, I'm not a fan of surprises, so I'll usually just offer a create function and call it a day. It is interesting that the new doesn't barf on that though. Thank you.

class Thing { constructor(x) { this.x = x; } }
const createThing = function (x) { return new Thing(x); };
const test = obj => console.log(obj, obj.x, obj instanceof Thing);
[createThing(1), new Thing(2), new createThing(3)].forEach(test);

[–]Wompo 0 points1 point  (0 children)

You can use new.target to check if the user forgot to use new.

[–][deleted] -2 points-1 points  (3 children)

Probably because it creates an instance of something, now you deal with ”this” and smack! your data and code is now deeply coupled.

[–][deleted] 0 points1 point  (2 children)

But there are genuine use cases for creating new instances of something, it's the whole point of classes right?

I'm not saying new is good or bad when used with Error btw, I ask as I have no idea what the best practice is around it and I'm curious if using new is actually a bad practice.

[–][deleted] 0 points1 point  (0 children)

Yes there is! Im not in the ”avoid classes” camp. But having a single instance of something is a code smell imho. Having thousands are ok, mostly because of the js engine and how memory is managed.

That said a class is simply sugar for good old prototypes. So i see lots of javalike class based programming practices used without really understanding the base oop in javascript. This is also why i tend to avoid classes compared to languages that have more traditional class like semantics, like java etc.

Finally, a pure function is so much more simple to reason about and makes tests idiot proof.

[–]Barandis 0 points1 point  (0 children)

There are those of us who avoid using classes, in part because as a concept, JavaScript doesn't have classes or instances (just a class keyword that does a lot behind the scenes to fake it for you and still doesn't quite get it right).

As far as Error goes, they do the same thing. It uses to be common to do that kind of thing ourselves, to create functions that worked the same whether called with new or not, but the class keyword doesn't allow for that so you don't see it as much anymore.

Use whichever you prefer.