1

I am facing a particular behavior of this object and looking for some help to understand how it works under the hood.

Two snippets:

  1. Standalone module, running this file as: node first.js
// first.js
function f1() {
  console.log('f1')
  this.f2()
}
function f2() {
  console.log('f2')
}
module.exports = {
  f1,
  f2
}
f1();

// Prints:
// f1
// this.f2 is not a function
  1. Two modules, running this file as: node second.js
// first.js
function f1() {
  console.log('f1')
  this.f2()
}
function f2() {
  console.log('f2')
}
module.exports = {
  f1,
  f2
}
// second.js
require('./first.js').f1()

// Prints:
// f1
// f2
  • Why is that happening in the first module?
  • I guess that functions within module.exports are wrapped into this object when the module is required. Any insight about this?
  • Is there any way to make the first snippet working using bind()?
  • Believe it or not, this is just normal behavior of the `this` keyword. See the [linked question's answers](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) for details, but I'll post a follow-up comment explaining this in the context of your code. – T.J. Crowder Dec 12 '20 at 11:58
  • From the linked question's answers you know that with a traditional function (ones created with the `function` keyword), `this` is controlled by *how the function is called*. The way you're calling `f1` in your first snippet (just `f1();` on its own) sets `this` to the default value, which is a reference to the global object in loose mode, or `undefined` in strict mode (`"use strict";`). Your code is loose mode code, so `this` during the call to `f1` is a reference to the global object, which has no `f2` property. *(cont'd)* – T.J. Crowder Dec 12 '20 at 12:00
  • But in your *second* snippet, the way you're calling `f1` is *via an object property*: `require('./first.js').f1()`. When you call a function you've just retrieved from an object property, `this` during the call refers to the object. In this case, that object is the module exports object -- which has an `f2` property with your `f2` function on it, so it works. *(cont'd)* – T.J. Crowder Dec 12 '20 at 12:02
  • Yes you could solve this with `bind`, but there's no reason to. In `f1`, to call `f2` just use `f2()`, not `this.f2()`, since `f1` closes over the environment where `f2` is declared, so `f2` is in scope for it. – T.J. Crowder Dec 12 '20 at 12:03
  • Recommendation: Switch to using ESM (JavaScript standard modules, `import` / `export` rather than `require` / the `exports` object), even the LTS version of Node.js supports ESM now. One benefit of ESM is that modules are strict mode by default, as with (nearly) all the JavaScript features added in ES2015 that introduce a new scope (`class`, for instance). Strict mode is a Good Thing™. :-) Happy coding!! *(Great question BTW!)* – T.J. Crowder Dec 12 '20 at 12:05
  • @T.J.Crowder thanks for your reply, I ll check linked questions and ESM modules too. Actually I would like to keep the way I am calling f2() with this.f2() for testing purposes (I am exporting private functions in order to be able to test them and mock them, but that's another discussion :D). How can I make use of bind to solve this? – miguelmartinezinf Dec 13 '20 at 16:55
  • Instead of `module.exports = { /*... */ };` do `f1 = f1.bind(module.exports); f2 = f2.bind(module.exports); module.exports.f1 = f1; module.exports.f2 = f2;` (`module.exports` starts out as a blank object, you don't have to create your own object for it). – T.J. Crowder Dec 13 '20 at 18:52
  • @T.J.Crowder thanks a lot! – miguelmartinezinf Dec 13 '20 at 19:46

0 Answers0