400

How do you call a function from within another function in a module.exports declaration?

app.js
var bla = require('./bla.js');
console.log(bla.bar());
bla.js
module.exports = {

  foo: function (req, res, next) {
    return ('foo');
  },

  bar: function(req, res, next) {
    this.foo();
  }

}

I'm trying to access the function foo from within the function bar, and I'm getting:

TypeError: Object # has no method 'foo'

If I change this.foo() to just foo() I get:

ReferenceError: foo is not defined

Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
k00k
  • 17,314
  • 13
  • 59
  • 86
  • 6
    I tested your code and have no errors. The bar function returns undefined because have no return statement. Are you sure you are testing correctly? – Ferchi Oct 02 '14 at 19:25
  • 1
    Tested in node version `v8.12.0` and does no longer throw the error. `bar` has no return statement so running `console.log(bla.bar())` simply returns `undefined` – VladNeacsu Apr 15 '19 at 19:00

10 Answers10

497

Change this.foo() to module.exports.foo()

Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
k00k
  • 17,314
  • 13
  • 59
  • 86
  • 3
    @NamNguyen Calling `exports.foo()` seems a little bit awkward and hard to read. – Afshin Mehrabani Jul 19 '14 at 12:20
  • 5
    I think that this is better than the accepted answer. If you define functions outside of the exports scope, it adds an extra level of indirection, and while it can be desirable sometimes, it makes it more complicated, to refactor, e.g. rename the function, of find usage of the function, etc. – Pierre Henry Sep 21 '15 at 14:48
  • 8
    `module.exports.foo()` and `exports.foo()` do not work for me with Node.js v5.8.0. – betweenbrain Jul 15 '16 at 15:35
  • 16
    exports.foo() is not working but module.exports.foo() is working with NodeJS v6.9.1 – Canser Yanbakan Nov 22 '16 at 14:04
  • This worked for me but instead of doing `module.exports = {...}` I had to do `exports.myFunction = function()` for each of the exported methods. – Joshua Pinter Jan 12 '17 at 21:01
  • 1
    `exports.foo` only works if you define an `exports` varible that references the `module.exports` object `const exports = module.exports = {}` and then set functions `foo` and `bar` as its methods `exports.foo = function() {}` and `exports.bar = function (){ exports.foo() }` here to reference `foo` in the `bar` use `exports.foo`. If you want to reference `foo` from `bar` inside `module.exports` object then use `module.exports.foo` inside `bar`. – pouya Jul 19 '17 at 12:24
  • @k00k: Can you please put link of your own answer to your question? It'll help us to get it over there itself instead of scrolling down to here. Thanks :) – Sandeep Jul 17 '18 at 12:45
  • You don't need your exports variable to reference module.exports, it is done for you: "The exports variable is available within a module's file-level scope, and is assigned the value of module.exports before the module is evaluated. It allows a shortcut, so that module.exports.f = ... can be written more succinctly as exports.f = ..." https://nodejs.org/api/modules.html#modules_exports_shortcut – ScottBro Nov 01 '18 at 15:09
  • its weird cant use `this` in module.exports – Fauzan Edris Mar 21 '21 at 14:02
202

You could declare your functions outside of the module.exports block.

var foo = function (req, res, next) {
  return ('foo');
}

var bar = function (req, res, next) {
  return foo();
}

Then:

module.exports = {
  foo: foo,
  bar: bar
}
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
Brett
  • 3,825
  • 3
  • 24
  • 27
131

You can also do this to make it more concise and readable. This is what I've seen done in several of the well written open sourced modules:

var self = module.exports = {

  foo: function (req, res, next) {
    return ('foo');
  },

  bar: function(req, res, next) {
    self.foo();
  }

}
Calvin Alvin
  • 2,448
  • 2
  • 16
  • 15
  • Is this Node.js version specific? I am trying this with v5.8.0 and it is logging undefined. – betweenbrain Jul 15 '16 at 15:38
  • 1
    @doublejosh Did... did you read the question? It's asking how you call one exported function from another. It has _nothing to do_ with access restrictions. – Nic May 16 '18 at 19:14
  • 1
    Yes I read it, please re-read. This answer makes foo() exported with the module, which goes against the point of a "local" function only called within the module. – doublejosh May 18 '18 at 19:34
  • This works great. I actually need foo() exported to be used outside, but also need to call it within sibling function. Thank you! – Paul Jan 30 '23 at 07:14
68

You can also save a reference to module's global scope outside the (module.)exports.somemodule definition:

var _this = this;

exports.somefunction = function() {
   console.log('hello');
}

exports.someotherfunction = function() {
   _this.somefunction();
}
Ville
  • 4,088
  • 2
  • 37
  • 38
42

Another option, and closer to the original style of the OP, is to put the object you want to export into a variable and reference that variable to make calls to other methods in the object. You can then export that variable and you're good to go.

var self = {
  foo: function (req, res, next) {
    return ('foo');
  },
  bar: function (req, res, next) {
    return self.foo();
  }
};
module.exports = self;
goozbox
  • 519
  • 6
  • 4
28
const Service = {
  foo: (a, b) => a + b,
  bar: (a, b) => Service.foo(a, b) * b
}

module.exports = Service
david_adler
  • 9,690
  • 6
  • 57
  • 97
21

Starting with Node.js version 13 you can take advantage of ES6 Modules.

export function foo() {
    return 'foo';
}

export function bar() {
    return foo();
}

Following the Class approach:

class MyClass {

    foo() {
        return 'foo';
    }

    bar() {
        return this.foo();
    }
}

module.exports = new MyClass();

This will instantiate the class only once, due to Node's module caching:
https://nodejs.org/api/modules.html#modules_caching

m.spyratos
  • 3,823
  • 2
  • 31
  • 40
  • and how does one call a static method with this approach? – Plixxer Jun 07 '18 at 20:55
  • @CodeofGod Just call it as you would call any other static method. In this case, if `foo` was static you would call it from inside `bar` like this: `MyClass.foo()`. – m.spyratos Jun 07 '18 at 21:08
  • yeah i get that, but how would you call it from a controller that is importing it like... const oAccounts = require("..."); – Plixxer Jun 07 '18 at 21:11
  • You can export the actual class, not an instance of the class. That way you can use its static methods. If you then need to use its instance methods though, then you will have to instantiate the class in your controller. – m.spyratos Jun 08 '18 at 00:44
8

To fix your issue, i have made few changes in bla.js and it is working,

var foo= function (req, res, next) {
  console.log('inside foo');
  return ("foo");
}

var  bar= function(req, res, next) {
  this.foo();
}
module.exports = {bar,foo};

and no modification in app.js

var bla = require('./bla.js');
console.log(bla.bar());
Akash Jain
  • 483
  • 5
  • 5
0

What I do is to create a standalone foo function and reference it in both places.

That way, it prevents any issue with this irrespective of using an arrow or regular function

function foo(req,res,next) {
  return ('foo');
}

Then I can reference foo at both places

module.exports = {

  foo, // ES6 for foo:foo

  bar: function(req, res, next) {
    foo();
  }

}
0

If you do like this, you will be losing your this object reference inside your calling function. For eg:

    module.exports.a = function () {
      return true
    }
    
    module.exports.b = function() {
      return this.a();
    }

here you will get the issue because when you call this.a(), it is referencing the this object of the b function.

To solve this your have to store your this object reference somewhere or use the arrow function, because the arrow function doesn't have there own this object so it will always reference the outer this object

To solve this, modify your function like this

    module.exports.a = function () {
      return true
    }
    
    module.exports.b = () => {
      return this.a();
    }
ritesh
  • 177
  • 2
  • 4