386

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
  • 13,762
  • 16
  • 86
  • 184
k00k
  • 16,544
  • 13
  • 57
  • 82
  • 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
  • @Ferchi thanks, I missed the same simple thing. – Soumyadip Das Dec 21 '20 at 09:04

9 Answers9

463

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

Let Me Tink About It
  • 13,762
  • 16
  • 86
  • 184
k00k
  • 16,544
  • 13
  • 57
  • 82
  • 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
  • 2
    a direct answer to the question – Kermit_ice_tea Mar 03 '16 at 23:24
  • 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
  • You are officially my hero. – educob May 20 '21 at 09:54
  • Thank you very much. This worked for me fine for which i was struggling for so many days. – Aadi Feb 21 '22 at 05:58
201

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
  • 13,762
  • 16
  • 86
  • 184
Brett
  • 3,765
  • 2
  • 25
  • 27
129

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,390
  • 2
  • 13
  • 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
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
  • 3,820
  • 2
  • 34
  • 36
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
27
const Service = {
  foo: (a, b) => a + b,
  bar: (a, b) => Service.foo(a, b) * b
}

module.exports = Service
david_adler
  • 7,408
  • 6
  • 45
  • 76
19

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,372
  • 2
  • 30
  • 36
  • 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
  • 443
  • 4
  • 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();
  }

}