Jan Peer
Jan Peer

Reputation: 305

JavaScript Class Weird Scoping

Assuming I have two files. One file with a class where the method hello just console.logs this:

// Class.js
class Test {
  constructor() {
    this.inside = true;
  }

  hello() {
    console.log('inside hello')
    console.log(this);
  }
}

module.exports = new Test();

and another file which executes the method hello of this class:

// index.js
const Test = require('./Class.js');

Test.hello();
// -> 'inside hello'
// -> { inside: true } 

Everything works as expected, the this in the hello() method has the correct scope. But, when I make a new instance of the class and export just hello of this new instance:

// Class.js
class Test {
  constructor() {
    this.inside = true;
  }

  hello() {
    console.log('inside hello')
    console.log(this);
  }
}

module.exports = (new Test()).hello; // <- just hello is exported

then the scoping of the hello() changed and it seems it is not a part of the class anymore:

// index.js
const hello = require('./index.js');

hello();
// -> 'inside hello'
// -> undefined

Is there a reason, why this single exported function acts so differently?


I tried it in Python, and it worked (maybe it does in other languages as well):

# Class.py
class Class:
  def __init__(self):
    self.test = 'hello'

  def hello(self):
    print('inside hello')
    print(self)

hello = Class().hello


# index.py
from Class import hello

hello()
# -> 'inside hello'
# -> <Class.Class instance at 0x10e26e488>

Upvotes: 2

Views: 85

Answers (2)

zoly01
zoly01

Reputation: 127

They have different context:
In first case, "hello" binds to "Test" object.
In second one, "hello" binds to "global scope" which is "undefined".
If you run second one in web browser, you will get "window" object which is the global context in browser.

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370729

When you call hello() standalone, it has no calling context - it's not being called from an object, when said object would ordinarily be its calling context. (such as Test.hello(); - the calling context would be Test in that line)

If you want to bind its calling context so that it's usable as a standalone function, you should export the bound function, such as:

const test = new Test();
module.exports = test.hello.bind(test);

Upvotes: 2

Related Questions