5

I'm attempting to write a node module in order to clean up my code and separate it out into different files.

Consider the below code:

module.exports = {
    Hello : function(request, reply) {
        return reply("Hello " + World());
    },
    World : function() {
        return "World";
    }
}

If I import the above module and use the Hello function as handler for a specific route, i get an HTTP 500 internal server error.

I've narrowed the problem down to the call to World(), if I change the Hello function to

Hello : function(request, reply) {
    return reply("Hello World");
}

Then it works fine, so it seems that it is being tripped up when calling another function from within the export object

Does anyone know why this is happening and how to resolve it?

Michael
  • 177
  • 3
  • 11
  • https://jsfiddle.net/rc62tuw8/ – Andy Aug 20 '17 at 16:13
  • Stange. It works in fiddle with this. appended, however it my application doesn't seem to like it – Michael Aug 20 '17 at 16:24
  • @Michael: It depends on how `Hello` is called. If it's *not* called as method of the exported object, `this` won't refer to the object. – Felix Kling Aug 20 '17 at 16:27
  • From where exactly do you call your `myModule.Hello function`..? – Redu Aug 20 '17 at 16:27
  • Its being called from my main app.js file, with the following server.route({ method: 'GET', path: '/user/new/{q}', handler: testy.Hello }); There seems to be something not quite right, however Ahmads answer works fine – Michael Aug 20 '17 at 16:35
  • @Michael Then i would say you to try `server.route({ method: 'GET', path: '/user/new/{q}', handler: testy.Hello.bind(testy)});` as mentioned in my answer. Of course in `testy` you should have `return reply("Hello " + this.World())` – Redu Aug 20 '17 at 16:43
  • Thanks, yes i think that would work too, but i think declaring the functions outside of the exports object looks cleaner. Very baffling, but it is working – Michael Aug 20 '17 at 16:50
  • Suggestion: better to code it in typescript for easier module management and preventing trivial errors. – Moses Aprico Aug 20 '17 at 19:24

3 Answers3

5

You should call it as follows:

module.exports = {
    Hello: function(request, reply) {
        return reply("Hello " + module.exports.World());
    },
    World: function() {
        return "World";
    }
}

If you are aiming for cleaner code, I suggest that you change the code to this:

function World() {
  return "World";
}
function Hello(request, reply) {
  return reply("Hello " + World());
}
module.exports = {
    Hello,
}

This will make your code more readable and you will only be exporting what you actually need. This question has other solutions to your issue.

3

Well let's demonstrate the this

this doesn't define the object that the function resides in. It defines from where the function is called. So while;

var obj = {
    Hello : function(request, reply) {
        return reply("Hello " + this.World());
    },
    World : function() {
        return "World";
    }
};
obj.Hello("test", console.log);

would work just fine; This wouldn't;

var obj = { Hello : function(request, reply) {
                      return reply("Hello " + this.World());
                    },
            World : function() {
                      return "World";
                    }
          };

setTimeout(obj.Hello,100,"test",console.log);

This is just because the obj.Hello will be assigned an argument in setTimeOut function's definition and that argument will be invoked as window being the this for that function. So you should instead do like;

var obj = { Hello : function(request, reply) {
                      return reply("Hello " + this.World());
                    },
            World : function() {
                      return "World";
                    }
          };

setTimeout(obj.Hello.bind(obj),100,"test",console.log);
//or 
setTimeout(obj.Hello.bind(obj,"test",console.log),100);
//or
setTimeout((x,y) => obj.Hello(x,y),100,"test",console.log);
Redu
  • 25,060
  • 6
  • 56
  • 76
  • This is very helpful explanation, i thought that the reply() function might be doing some 'magic' behind the scenes which was screwing it up, however Ahmads answer (2nd part) works fine and its pretty much exactly the same, just different syntax. I'm really baffled as to the cause, but nonetheless it is working – Michael Aug 20 '17 at 16:45
  • @Michael See my comment under your question. It should work regardless whatever magic `reply` does provided that you have `return reply("Hello " + this.World());` instruction in your `testy` module's `Hello` method. – Redu Aug 20 '17 at 16:52
2

You'll need to add this to your invocation of World() -

module.exports = {
    Hello : function(request, reply) {
        return reply("Hello " + this.World());
    },
    World : function() {
        return "World";
    }
}

World is an attribute of the export object, not a variable within the accessible scope - so you need to specify that the function belongs to this.

skwidbreth
  • 7,888
  • 11
  • 58
  • 105