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
How to Toggle Class Using Pure JavaScript in HTML
Most Elegant Way to Force a Textarea Element to Line-Wrap, *Regardless* of Whitespace
Getelementsbyclassname to Change the Style of Elements When Event Occurs
Convert CSS Width String to Regular Number
Using Queryselectorall(). Is the Result Returned by the Method Ordered
Why Browser Is Returning Empty String on Style.Height ? How to Get Actual Height of an Element
Jquery How to Apply CSS to Selected Text
Jquery Select Pseudo-Element :After
Add CSS Styled Marker to Google Maps
How to Reliably Get Screen Width with the Scrollbar
Jquery - How to Disable the Entire Page
Getcomputedstyle (Or) $.Css(Map) <-- to Get Every Style Declaration
Perspective Transform of Svg Paths (Four Corner Distort)
How to Import Jquery Using Es6 Syntax