Search code examples
javascriptnode.jsv8

Node won't run example from Eloquent Javascript, v8 will. What's the deal?


The function below is copied verbatim from Ch. 10 of Eloquent Javascript, and it runs perfectly with the v8 interpreter. However, it bombs out in Node with the object weekDay undefined. It also runs fine in the sandbox interpreter provided by the book. Can someone explain what's up?

(function(exports) {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
               "Thursday", "Friday", "Saturday"];

  exports.name = function(number) {
    return names[number];
  };
  exports.number = function(name) {
    return names.indexOf(name);
  };
})(this.weekDay = {});

console.log(weekDay.name(weekDay.number("Saturday")));

Solution

  • It's because this in a Node module isn't pointing to the global object. It points to the exports of that module. This means weekDay isn't available as a global variable.

    // ---------v
    console.log(exports.weekDay.name(weekDay.number("Saturday")));
    

    or

    // ---------v
    console.log(this.weekDay.name(weekDay.number("Saturday")));
    

    To get a broad (and simplified) view of what a node module looks like, it basically takes your code and puts it in an IIFE.

    So if this is your module...

    this.foo = "bar"
    console.log(exports.foo); // "bar"
    

    it works because it's actually something like this...

    var exports = {};    // Generated by Node
    (function(exports) { // Generated by Node
    
        this.foo = "bar"
        console.log(exports.foo); // "bar"
    
    }).call(exports, exports); // Generated by Node
    

    Where the extra lines of code are generated by Node. You can see that it creates an object which it uses as both the this value and the exports parameter of the IIFE function.

    There's a bit more that they pass in to the IIFE as well, but this shows the basic idea.