Es6: Call Class Constructor Without New Keyword

call a methods of a class without using NEW keyword inside other class node js

There is no big magic to it. Since the OP just wants to reuse prototypal Main methods, one is going to explicitly delegate the method/s of interest which was/were provided/accessed before via Main.prototype ...

class Main {
constructor(args) {
this.hooks = {};
}
add_hooks(name, func) {
if (!this.hooks[name]) {
this.hooks[name] = [];
}
this.hooks[name].push(func);
}
call_hooks(name, ...params) {
if (this.hooks[name]) {
this.hooks[name].forEach(func => func(...params));
}
}
}

// const Main = require("./main.js");

class Person {

// // ... either add `hooks` as public property at instantiation time ...
// hooks = {};

exec() {
const ref = Main.prototype;
ref.add_hooks.call(this, "jump", console.log.bind(console, "this will log"));
}
}

// ... or add `hooks` via additional glue code ...
function createPersonWithHooksAndExecute() {
const type = new Person();

type.hooks = {};
type.exec();

return type;
}
const someone = createPersonWithHooksAndExecute();
console.log({ someone });

// this will log
Main.prototype.call_hooks.call(someone, "jump");
.as-console-wrapper { min-height: 100%!important; top: 0; }

ES6: Instantiate class without calling constructor

You can add a static method create, that create an Object from the class prototype. Something like that should work:

class Test {
constructor(foo) {
this.foo = foo
}
static create() {
return Object.create(this.prototype)
}
}

const a = new Test('bar') // call constructor
const b = Test.create() // do not call constructor
console.log(a.foo, a instanceof Test) // bar, true
console.log(b.foo, b instanceof Test) // undefined, true

Calling ES6 class constructor from class static method

TestClass is the constructor function. TestClass.constructor is the builtin Function, which when called constructs a new empty function (what you are logging).

The TestClass constructor can also be accessed as TestClass.prototype.constructor, that's what you probably meant:

static getInstance(){
if (!instance) {
instance = TestClass.prototype.constructor();
}
return instance;
}

This will of course throw an exception that you cannot call class constructors without new.

You also should simplify to new TestClass. Or even better, in case you want to support subclassing, new this - notice that this in static method refers to the class (constructor) itself.

I'm trying to do my implementation of singleton pattern in JS ES6 class

Please don't. Singletons are bad practice. If your class doesn't have any state, and there's just one instance anyway, don't use a class. Just write

export function testMethod() {
console.log('test');
}
// Yes, that's the whole file!

If you insist on lazily constructing the module, I would recommend

let instance;
/*default*/ export function getInstance() {
return instance || (instance = { // use a simple object literal
testMethod(){
console.log('test');
}
});
}

That said, if you insist on making a "private" constructor I would pass a token:

const internal = Symbol("creation token for TestClass");
export class TestClass {
constructor(token) {
if(token !== internal) {
throw new Error("Please use the TestClass.getInstance() static method instead");
}
}

static getInstance(){
return new TestClass(internal); // make sure not to call `this`, otherwise subclassing could leak the token
}
}

But you should never really need that.

How to use es6 constructor instructions with a different context

As the comments and yourself have pointed out, trying to invoke class constructors with a custom this context is really not something you want to attempt if there is any way around it. This was made hard intentionally!

If for some reasons this is unavoidable enough to justify tricky workarounds, you can find two partial solutions below. They are both imperfect in their own ways - depending on your exact situation one of them may still fit your needs.


Workaround 1

While it is impossible to set this directly in a constructor call, it is possible to set the prototype of this to an object of your choice.

To do so you can use Reflect.construct() to call the internal [[Construct]] method with a custom new.target value. this will then get initialised to an object inheriting from new.target.prototype.

Building on your example:

function ES5() {    this.foo = 'foo';}
class ES6 { constructor() { this.bar = 'bar'; }}
let b = new ES5();
function TemporaryHelperConstructor() {}TemporaryHelperConstructor.prototype = b;
b = Reflect.construct( ES6, [], TemporaryHelperConstructor ); // The third argument corresponds to the value of new.target
console.log( b.foo + b.bar ); // foobar !


Related Topics



Leave a reply



Submit