EvgeniySharapov
EvgeniySharapov

Reputation: 3496

Referencing static method in Class exported from Node JS module

The question is how to refer to other static methods from a static method of a class exported from NodeJS module? Here's a setup. I have following modules: test1.js

var Parent = class  {
    static smethod1 () {
        return this.smethod2();
    }

    static smethod2 () {
        return "Testing tube";
    }
}

module.exports = {
    Parent:Parent
}

Then I have test2.js that requires this module

var mod = require('./test1');
var Parent = mod.Parent;

module.exports = {
    sm1: Parent.smethod1,
    sm2: Parent.smethod2
}

Finally, I have a code that is being run in run.js

var test2 = require('./test2');

console.log(test2.sm1());

Naturally, I want to see "Testing tube" line printed out. I am getting error

        return this.smethod2();
                    ^

TypeError: this.smethod2 is not a function 

Of course, there's shenanigans on NodeJS where this refers to a module, but shouldn't it be referring to a function instead ? Is there way to refer to static method smethod2 from smethod1 with current setup ? If not, what are the workarounds ?

Upvotes: 0

Views: 2249

Answers (1)

neurozero
neurozero

Reputation: 1056

The this keyword is kind of weird in JavaScript, and doesn't always refer to your instance like in most class based languages. In your case, when you call test2.sm1(), this is set to the test2 object, which is

{
    sm1: Parent.smethod1,
    sm2: Parent.smethod2
}

That object does not have a smethod2 function.

this gets set based on how a function is called in JavaScript, specifically with whatever is before the '.': ->test2<-.sm1().

There are several workarounds. First, after defining the Parent class, you could bind this for that function to the class:

var Parent = class  {
    static smethod1 () {
        return this.smethod2();
    }

    static smethod2 () {
        return "Testing tube";
    }
}

// bind `this` to `Parent`
Parent.smethod1 = Parent.smethod1.bind(Parent);

module.exports = {
    Parent:Parent
}

Alternatively, you could pass Parent as an argument to call or apply, which sets this manually for just that one invocation:

var Parent = require('./test1');
var test2 = require('./test2');

// call `test2.sm1` with a context of `Parent`    
console.log(test2.sm1().call(Parent));

Upvotes: 2

Related Questions