ES6: call class constructor without new keyword
JavascriptConstructorEcmascript 6InstanceJavascript Problem Overview
Given a simple class
class Foo {
constructor(x) {
if (!(this instanceof Foo)) return new Foo(x);
this.x = x;
}
hello() {
return `hello ${this.x}`;
}
}
Is it possible to call the class constructor without the new
keyword?
Usage should allow
(new Foo("world")).hello(); // "hello world"
Or
Foo("world").hello(); // "hello world"
But the latter fails with
Cannot call a class as a function
Javascript Solutions
Solution 1 - Javascript
Classes have a "class body" that is a constructor.
If you use an internal constructor()
function, that function would be the same class body as well, and would be what is called when the class is called, hence a class is always a constructor.
Constructors requires the use of the new
operator to create a new instance, as such invoking a class without the new
operator results in an error, as it's required for the class constructor to create a new instance.
The error message is also quite specific, and correct
> TypeError: Class constructors cannot be invoked without 'new'
You could;
- either use a regular function instead of a class1.
- Always call the class with
new
. - Call the class inside a wrapping regular function, always using
new
, that way you get the benefits of classes, but the wrapping function can still be called with and without thenew
operator2.
1)
function Foo(x) {
if (!(this instanceof Foo)) return new Foo(x);
this.x = x;
this.hello = function() {
return this.x;
}
}
2)
class Foo {
constructor(x) {
this.x = x;
}
hello() {
return `hello ${this.x}`;
}
}
var _old = Foo;
Foo = function(...args) { return new _old(...args) };
Solution 2 - Javascript
As others have pointed out ES2015 spec strictly states that such call should throw TypeError, but at the same time it provides feature that can be used to achieve exactly the desired result, namely https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy">Proxies</a>;.
Proxies allows us to virtualize over a concept of an object. For instance they can be used to change some behaviour of particular object without affecting anything else.
In your specific use case class Foo
is Function object
which can be called -- this normally means that body of this function will be executed. But this can be changed with Proxy
:
const _Foo = new Proxy(Foo, {
// target = Foo
apply (target, thisArg, argumentsList) {
return new target(...argumentsList);
}
});
_Foo("world").hello();
const f = _Foo("world");
f instanceof Foo; // true
f instanceof _Foo; // true
(Note that _Foo
is now the class you want to expose, so identifiers should probably be the other way round)
If run by browser that support Proxies, calling _Foo(...)
will now execute apply
trap function instead of the orignal constructor.
At the same time this "new" _Foo
class is indistinguishable from original Foo
(apart from being able to call it as a normal function). Similarily there is no difference by which you can tell object created with Foo
and _Foo
.
The biggest downside of this is that https://babeljs.io/docs/learn-es2015/#proxies">it cannot be transpilled or pollyfilled, but still its viable solution for having Scala-like class apply in JS in the future.
Solution 3 - Javascript
Here's a pattern I've come across that really helps me. It doesn't use a class
, but it doesn't require the use of new
either. Win/Win.
const Foo = x => ({
x,
hello: () => `hello ${x}`,
increment: () => Foo(x + 1),
add: ({x: y}) => Foo(x + y)
})
console.log(Foo(1).x) // 1
console.log(Foo(1).hello()) // hello 1
console.log(Foo(1).increment().hello()) // hello 2
console.log(Foo(1).add(Foo(2)).hello()) // hello 3
Solution 4 - Javascript
No, this is not possible. Constructors that are created using the class
keyword can only be constructed with new
, if they are [[call]]ed without they always throw
a TypeError
1 (and there's not even a way to detect this from the outside).
1: I'm not sure whether transpilers get this right
You can use a normal function as a workaround, though:
class Foo {
constructor(x) {
this.x = x;
}
hello() {
return `hello ${this.x}`;
}
}
{
const _Foo = Foo;
Foo = function(...args) {
return new _Foo(...args);
};
Foo.prototype = _Foo.prototype;
}
Disclaimer: instanceof
and extending Foo.prototype
work as normal, Foo.length
does not, .constructor
and static methods do not but can be fixed by adding Foo.prototype.constructor = Foo;
and Object.setPrototypeOf(Foo, _Foo)
if required.
For subclassing Foo
(not _Foo
) with class Bar extends Foo …
, you should use return Reflect.construct(_Foo, args, new.target)
instead of the new _Foo
call. Subclassing in ES5 style (with Foo.call(this, …)
) is not possible.
Solution 5 - Javascript
i just made this npm module for you ;)
https://www.npmjs.com/package/classy-decorator
import classy from "classy-decorator";
@classy()
class IamClassy {
constructor() {
console.log("IamClassy Instance!");
}
}
console.log(new IamClassy() instanceof IamClassy()); // true
console.log(IamClassy() instanceof IamClassy()); // true
Solution 6 - Javascript
class MyClass {
constructor(param) {
// ...
}
static create(param) {
return new MyClass(param);
}
doSomething() {
// ...
}
}
MyClass.create('Hello World').doSomething();
Is that what you want?
If you need some logic when creating a new instance of MyClass
, it could be helpful to implement a "CreationStrategy", to outsorce the logic (for example complex builder logic with validation)
Edit: As discussed in the comments It does not make sense to create some sort of Builder Pattern with a separate class in JavaScript. Removed related example.
Solution 7 - Javascript
Here's a where you can use a 'scope safe constructor' Observe this code:
function Student(name) {
if(this instanceof Student) {
this.name = name;
} else {
return new Student(name);
}
}
Now you can create a Student object without using new as follows:
var stud1 = Student('Kia');
Solution 8 - Javascript
Dug up this one in the draft
> Constructors defined using class definition syntax throw when called as functions
So I guess that's not possible with classes.
Solution 9 - Javascript
Call class constructor manually can be usefull when refactoring code (having parts of the code in ES6, other parts beeing function & prototype definition)
I ended up with a small, yet usefull boilerplate, slicing the constructor into another function. Period.
class Foo {
constructor() {
//as i will not be able to call the constructor, just move everything to initialize
this.initialize.apply(this, arguments)
}
initialize() {
this.stuff = {};
//whatever you want
}
}
function Bar () {
Foo.prototype.initialize.call(this);
}
Bar.prototype.stuff = function() {}
Solution 10 - Javascript
I had problems extending classes converted with the transformation function mentioned in some other answers. The issue seems to be that node (as of v9.4.0) doesn't properly support the argument spread operator ((...args) =>
).
This function based on the transpiled output of the classy-decorator (mentioned in another answer) works for me and doesn't require support for decorators or the argument spread operator.
// function that calls `new` for you on class constructors, simply call
// YourClass = bindNew(YourClass)
function bindNew(Class) {
function _Class() {
for (
var len = arguments.length, rest = Array(len), key = 0;
key < len;
key++
) {
rest[key] = arguments[key];
}
return new (Function.prototype.bind.apply(Class, [null].concat(rest)))();
}
_Class.prototype = Class.prototype;
return _Class;
}
Usage:
class X {}
X = bindNew(X);
// or
const Y = bindNew(class Y {});
const x = new X();
const x2 = X(); // woohoo
x instanceof X; // true
x2 instanceof X; // true
class Z extends X {} // works too
As a bonus, TypeScript (with "es5" output) seems to be fine with the old instanceof
trick (well, it won't typecheck if used without new
but it works anyhow):
class X {
constructor() {
if (!(this instanceof X)) {
return new X();
}
}
}
because it compiles it down to:
var X = /** @class */ (function () {
function X() {
if (!(this instanceof X)) {
return new X();
}
}
return X;
}());
Solution 11 - Javascript
Alright I have another answer here, and I think this one is pretty innovative.
Basically, the problem with doing something similar to Naomik's answer is that you create functions each and every time you chain methods together.
EDIT: This solution shares the same problem, however, this answer is being left up for educational purposes.
So here I'm offering a way to merely bind new values to your methods--which are basically just independent functions. This offer the additional benefit of being able to import functions from different modules into the newly constructed object.
Okay, so here it goes.
const assoc = (prop, value, obj) =>
Object.assign({},obj,{[prop]: value})
const reducer = ( $values, accumulate, [key,val] ) => assoc( key, val.bind( undefined,...$values ), accumulate )
const bindValuesToMethods = ( $methods, ...$values ) =>
Object.entries( $methods ).reduce( reducer.bind( undefined, ...$values), {} )
const prepareInstance = (instanceMethods, staticMethods = ({}) ) => Object.assign(
bindValuesToMethods.bind( undefined, instanceMethods ),
staticMethods
)
// Let's make our class-like function
const RightInstanceMethods = ({
chain: (x,f) => f(x),
map: (x,f) => Right(f(x)),
fold: (x,l,r) => r(x),
inspect: (x) => `Right(${x})`
})
const RightStaticMethods = ({
of: x => Right(x)
})
const Right = prepareInstance(RightInstanceMethods,RightStaticMethods)
Now you can do
Right(4)
.map(x=>x+1)
.map(x=>x*2)
.inspect()
You can also do
Right.of(4)
.map(x=>x+1)
.map(x=>x*2)
.inspect()
You also have the added benefit of being able to export from modules as such
export const Right = prepareInstance(RightInstanceMethods,RightStaticMethods)
While you don't get ClassInstance.constructor
you do have FunctorInstance.name
(note, you may need to polyfill Function.name
and/or not use an arrow function for export for browser compatibility with Function.name
purposes)
export function Right(...args){
return prepareInstance(RightInstanceMethods,RightStaticMethods)(...args)
}
PS - New name suggestions for prepareInstance welcomed, see Gist.
https://gist.github.com/babakness/56da19ba85e0eaa43ae5577bc0064456
Solution 12 - Javascript
As pointed out by you and others
Foo("world").hello();
fails with an error because it is an error, according to rules of ES6 syntax.
Others pointed out that
(new Foo("world")).hello();
works but is clunky because
- It needs the 'new' AND
- It needs the extra parenthesis.
I agree it is clunky. So I'm often using this solution instead:
-
In your class Foo, create a static method named 'new':
static new (...args) { return new this (...args); }
-
Use it like this:
Foo.new("world").hello();
This way I hide the "clunkiness" inside this static method 'new()'.
Note that this method new() is generic, it will work as is also when inherited to sub-classes. If you need to customize it in a subclass you can first call:
super.new(...args)
and then add any other stuff you need in the method in a subclass, before returning its result.
Solution 13 - Javascript
A recapped working "one-line" solution for ES6: explained
The answer posted above by Bergi is basically correct.
TLDR; skip to the end for the one-liner solution
Bergi's answer may seem a unclear when reading it. So, here is a more expanded code-sample that illustrates TWO new ES6 features to achieve the desired goals.
Together, they let a single function C
(below) provide the dual-role of a factory and new-able fn; which constructs a B
inst that derives from a A
.
> The B
constructor utilizes super
handling to invoke the A
constructor with initialization arguments. In our final #3 - #4 examples constructed by C
.
> The A
constructor demonstrates the semantics of the new.target
psuedo-var to discover new
was actually invoked with B
.
First, we will make use of ES6 new.target
psuedo-var that gives us the RHS
of a new RHS()
expression.
> Technically, we could have gotten new.target
as this?.__proto__?.constructor
; they are equivalent.
Second, we will make use of ES6 Reflect.construct
. Which is crucial to working around the ES6 class constructor invocation constraints; if we are bound and determined to not use new RHS(...)
.
Test the following and see for yourself its output (also provided in #1-4 below).
class A {
constructor(...a) {
const descendentType = new.target;
console.log(`A's constructor seeing 'new' invoked on ${descendentType?.name} with args: %o`,a);
}
}
class B extends A {
constructor(...a) {
super(...a);
}
}
// C is our DUAL mode Factory
function C(...a) {
console.log(`C's new.target => ${new.target?.name}`);
const inst = new.target ? Reflect.construct(B, a) : new B(...a);
console.log(`C has constructed a ${inst.__proto__.constructor.name} inst`);
return inst;
}
Which we can then invoke it in the following ways:
new A('NEW-A()')
- output => "A's constructor seeing 'new' invoked on A with args: ['NEW-A()']"
new B('NEW-B()')
- output => "A's constructor seeing 'new' invoked on B with args: ['NEW-B()']"
new C('NEW-C()')
- output => "C's new.target => C"
- output => "A's constructor seeing 'new' invoked on B with args: ['NEW-C()']"
- output => "C has constructed a B inst"
C('PLAIN-C()')
- output => "C's new.target => undefined"
- output => "A's constructor seeing 'new' invoked on B with args: ['PLAIN-C()']"
- output => "C has constructed a B inst"
Where #3 and #4 achieve the originally desired goals.
C
looks like:
The simplified function C(...a) {return Reflect.construct(B, a);}
OR - if 3rd arg of Reflect.construct
not utilized for init.
function C(...a) {return new B(...a);}
>Beware: C
must be a function not a class
for this to both be allowed, and to work returning an alternate this
on a new C()
invocation, etc.
Also to circumvent strict mode rules for arguments.callee
requires using a closure (smalltalk-block. Illustrated below:
class B extends A {
// embedding within a class and generically referencing it requires =>
static C = (() => {
const $class = this; return function(...a) {
return Reflect.construct($class, a);}})();
// Read more on `Reflect.construct` 3rd argument to see more capabilities
// for why it does MORE than just `new $class(...a)` would do.
}
exports.C = B.C;
>⛐⚠️⛐ You could do some awful things like fiddle the __proto__
on the resulting inst
and change out its constructor
and name
. Which would make it look and feel like a real subclass C
of B
depending on how far you want to go to manipulate the object-model. The subtleties abound in what happens with getters/setters
, super
and #
privates. But for much of that you can STAY ES6 CLEAN and get clever with using extends
and providing a template superclass flattened mixin tree; which I do a lot of in efekt for supporting tiny-but-complete µhtml reactive custom-elements parts and related PWA app models and responsive dynamic just-in-time versioned code bundling from EdgeS ESS backend servers. As in ... const M = $class => class extends $class {...}
.
I posted this to help explain the semantics and a working ES6 solution, which is what I use to support subclassing My motivations...
Promise
to provide FutureValue
with better workflow handling capabilities in my github efekt library (EdgeS Front End Kit library).
Solution 14 - Javascript
Calling the class constructor without the new
keyword is not possible.
The error message is quite specific.
See a blog post on 2ality and the spec:
However, you can only invoke a class via new, not via a function call (Sect. 9.2.2 in the spec):
> Point()
TypeError: Classes can’t be function-called
Solution 15 - Javascript
I'm adding this as a follow up to a comment by naomik and utilizing on the method illustrated by Tim and Bergi. I'm also going to suggest an of
function to use as a general case.
To do this in a functional way AND utilize the efficiency of prototypes (not re-create all method each time a new instance is created), one could use this pattern
const Foo = function(x){ this._value = x ... }
Foo.of = function(x){ return new Foo(x) }
Foo.prototype = {
increment(){ return Foo.of(this._value + 1) },
...
}
Please note that this is consistent with fantasy-land
JS specs
https://github.com/fantasyland/fantasy-land#of-method
I personally feel that it is cleaner to use the ES6 class syntax
class Foo {
static of(x) { new Foo(x)}
constructor(x) { this._value = x }
increment() { Foo.of(this._value+1) }
}
Now one could wrap this in a closure as such
class Foo {
static of(x) { new _Foo(x)}
constructor(x) { this._value = x }
increment() { Foo.of(this._value+1) }
}
function FooOf (x) {
return Foo.of(x)
}
Or rename FooOf
and Foo
as desired, ie the class could be FooClass
and the function just Foo
, etc.
This is better than place the class in the function because creating new instances doesn't burden us with creating new classes as well.
Yet another way is to create a an of
function
const of = (classObj,...args) => (
classObj.of
? classObj.of(value)
: new classObj(args)
)
And then do something like of(Foo,5).increment()
Solution 16 - Javascript
Still finding interesting ways to use instanceof
without relying on new
or class
keywords. In this example program, we compute the 100,000th fibonacci number in less than one second. The result is over 20,000 digits long -
const fib = x =>
Loop // <- no `new`
( (n, a, b) =>
n <= 0n
? String(a) // <- no `new`
: Recur(n - 1n, b, a + b) // <- no `new`
, BigInt(x) // <- no `new`
, 0n
, 1n
)
function Loop (f, ...init)
{ let r = f(...init)
while (r instanceof Recur) // <- instanceof works
r = f(...r)
return r
}
function Recur (...v)
{ return Object.create // <- not a class, but works
( Recur.prototype // <- set prototype
, { constructor: { value: Recur } // <- set constructor
, [Symbol.iterator]: { value: _ => v.values() } // <- whatever you want
}
)
}
document.body.textContent = fib(100000)
body { overflow-wrap: anywhere; }
I don't know why I haven't thought of this before -
function atom (T, v)
{ return Object.assign
( Object.create
( T.prototype
, { constructor: { value: T } }
)
, v
)
}
function pair (car, cdr)
{ return atom(pair, { car, cdr }) }
const p =
pair(1, 2)
console.log(p)
console.log(p instanceof pair)
Output -
{
"car": 1,
"cdr": 2
}
true
Solution 17 - Javascript
I wrote a small helper function which solves this problem. It effectively converts an ES6 class into an older ES5 constructor function which isn't subject to the same ruleset. This way you can create constructors which don't need new
. You can also overload constructors in a similar way to the builtin Number
, String
etc.
function callableConstructor(c, f) {
function ret(...args) {
if(new.target) {
return new c(...args)
}
return f(...args)
}
ret.prototype = c.prototype
ret.prototype.constructor = ret
return ret
}
Test it below:
function callableConstructor(c, f) {
function ret(...args) {
if(new.target) {
return new c(...args)
}
return f(...args)
}
ret.prototype = c.prototype
ret.prototype.constructor = ret
return ret
}
// Usage
class Foo {
constructor(a, b) {
this.a = a
this.b = 2 * b
}
f() {
return this.a + this.b
}
}
Foo = callableConstructor(Foo, (...args) => new Foo(...args))
let foo = new Foo(2, 3)
console.log(foo) // Foo { a: 2, b: 6 }
console.log(foo.f()) // 8
console.log(foo instanceof Foo) // true
foo = Foo(2, 3)
console.log(foo) // Foo { a: 2, b: 6 }
console.log(foo.f()) // 8
console.log(foo instanceof Foo) // true
Solution 18 - Javascript
I came at this issue because I encountered the no-new
"do not use new for side effects" eslint rule - which turns out it's a bad practice to use new for an object that is immediately discarded.
I still wanted to use the class syntax because I like it, but I agree that a regular class with new keyword for something that does not produce an object can be confusing.
The solution for me was simple. Define an unexported class in a module and export a function that instatinates it.
class SideEffects {
constructor() {
}
// ...
}
export function addSideEffects() {
// eslint-disable-next-line no-new
new SideEffects();
}
Yes, we are still using the new
keyword, but it's used internally in the module and it's obvious from reading the module file that it's not a regular class - and the exported function also makes it clear that it does not create an object.
Solution 19 - Javascript
This might be a little contrived, but it works
function Foo(x){
"use strict"
class Bar {
constructor(x) {
if (!(this instanceof Bar)) return new Bar(x);
this.x = x;
}
hello() {
return `hello ${this.x}`;
}
}
return new Bar(x)
}
Foo("world").hello()
Solution 20 - Javascript
You can't use a class without the new constructor, in my case I didn't want to use the new
constructor any time I wanted to use my class, so what you can do is to wrap your class as follows (in my case it's a Dates utils library):
const defaultOptions = {
defaultFormatOptions: 'dd/MM/yyyy'
}
class DatesClass {
constructor(date = new Date(), options) {
this.date = date
this.options = { ...defaultOptions, ...options }
}
get value() {
return this.date
}
add() {}
...
}
export default (date, options) => new DateClass(date, options)
// then you can use it as follow
import dates from 'path/to/yourClass/from/above'
dates(new Date()).add({ unit: 'day', qty: 2}).value