'TypeError: undefined is not a function when switching between modules

I keep getting this problem in Node, where my application crashes when I call functions from each other.

I made this minimal working example (working as it gives me an error):

Run module

var module2 = require('./module2'); var data = 'data'; module2.doStuff(data); 

Module2

 var module3 = require('./module3'); function doStuff(data){ // Stuff happens to 'data' module3.takeStuff(data); } function doSomethingElse(data){ console.log(data); } module.exports = { doStuff: doStuff, doSomethingElse: doSomethingElse }; 

Module3

 var module2 = require('./module2'); function takeStuff(data){ // Stuff happens to 'data' module2.doSomethingElse(data); // I get the type error here } module.exports = { takeStuff: takeStuff }; 

The error I get is:

 module2.doSomethingElse(data); // I get the type error here ^ TypeError: undefined is not a function 

start module calls a function in module2 , which ultimately calls a function in module3 , which in turn calls a function in module2 .

All modules are properly required, and it finds the first method in module2 just fine.

What happens here and how to do it if you need to get a function from the module that came with?

EDIT

Debugging shows me that the module exists, but it is empty except for the prototype that it has. Why is my question? Inside Node / JavaScript, what's going on here?

+8
javascript typeerror
source share
2 answers

You have a circular link, module 2 depends on module 3, which depends on module 2, which depends on module 3 (etc.). Therefore, trying to enable module 3 for module 2 , it cannot complete it, because module 3 must be enabled.

From https://nodejs.org/api/modules.html#modules_cycles :

If there are calls to circle require (), the module may not complete execution when it returns.

To prevent an infinite loop, an incomplete copy of a.js export object is returned to b.js.

Thus, the module is available, but incomplete (which explains that you get only a prototype). Circular links are the smell of code, still try to avoid it :)

However, if you put both modules 2 and 3 depending on your starting module, it should work anyway.

 var module2 = require('./module2'); var module3 = require('./module3'); var data = 'data'; module2.doStuff(data); 
+4
source share

This problem here can be easily fixed, while maintaining the structure of your application (which is good with respect to circular links).

You just need to save the default export object, which is provided to your modules by the system. Do not change it with module.exports = {...} .

The following should work:

Run module

 var module2 = require('./module2'); var data = 'data'; module2.doStuff(data); 

Module 2

 var module3 = require('./module3'); exports.doStuff = function doStuff(data){ // Stuff happens to 'data' module3.takeStuff(data); }; exports.doSomethingElse = function doSomethingElse(data){ console.log(data); }; 

Module 3

 var module2 = require('./module2'); exports.takeStuff = function takeStuff(data){ // Stuff happens to 'data' module2.doSomethingElse(data); // I get the type error here }; 

Description

I will try to explain what comes from the first line of your starting point:

  • In start.js, you need module2, and it is not loaded yet: the code from module2.js is executed
  • In module2.js you need module 3 and it is not loaded yet: the code from module3.js is executed
  • In module3.js, you need module2, and it is already loaded: the variable module2 now contains the export object from module2.
  • The rest of module 3 runs and you change your export object with module.exports = {...}
  • In module2.js, the variable module3 now contains the export object from module 3.
  • The rest of module2.js is executed, and you change your export object with module.exports = {...}
  • In start.js, the variable module2 now contains the export object from module 2.

The problem here is between points 3 and 6. Module 3 gets the export of module 2 (3) before you change the link to it (6). Using exports.method = ... solves the problem because the export object never changes.

+6
source share

All Articles