2

I am trying to understand how scope works with node modules. I have an IIFE to initialize a LinkedList, which uses Node object for each element.
using IIFE to avoid polluting global scope

After IIFE, where does the Node go? Is there any way I can access Node in require object i.e. test class?

linkedList.js

(function LinkedListInit() {
    module.exports = new LinkedList();

    function LinkedList() {
        this.head;
    }

    // LinkedList Node
    function Node(data, next) {
        this.data = data;
        this.next = next;
    }

    LinkedList.prototype.insert = insert;

    function insert(data) {
        var curr = this.head,
            newNode = new Node(data);
            
        if (this.head == null) {
            this.head = newNode;
        } else {
            while (curr.next != null) {
                curr = curr.next;
            }
            curr.next = newNode;
        }
        return this;
    }
}());

linkedListTest.js

var linkedList = require('../../js/ds/linkedList');
// Test cases for linkedList.insert(val); works fine.

// Can I access Node here?
1
  • What are you trying to do? Commented Mar 30, 2017 at 18:15

3 Answers 3

3

Generally, any functions and variables defined in your ES6 module are module scoped, i.e. your IIFE is not necessary in this case. Node or insert will not be accessible from outside the module unless they are explicitly exported via module.exports.


With that in mind, unit tests won't be able to simply access the implementation details either. If you want to test Node separately, the cleanest way would likely to move it to a separate module and import it into LinkedList:

// Node.js
function Node(data, next) {
    this.data = data;
    this.next = next;
}

module.exports = Node;


// LinkedList.js
var Node = require('./Node');

function LinkedList() {
    this.head;
}
LinkedList.prototype.insert = function(data) {
    var curr = this.head,
        newNode = new Node(data);

    if (this.head == null) {
        this.head = newNode;
    } else {
        while (curr.next != null) {
            curr = curr.next;
        }
        curr.next = newNode;
    }
    return this;
}

module.exports = LinkedList;


// NodeTest.js
var Node = require('./Node');

var node = new Node('foo');
// ...


// LinkedListTest.js
var LinkedList = require('./LinkedList');

var linkedList = new LinkedList();
linkedList.insert('foo');
// ...
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @timo, you actually helped me in improving the way I use module.exports. I used to do module.exports = new LinkedList(). Now I think I was doing it wrong all the time.
1

You're scope is already contained within the module - except for what you choose to export, so you don't really need the IIFE.

If you wanted it to work with an IIFE, you would have to attach the IIFE to module.exports rather than wrapping your IIFE around it. Something like...

module.exports = (function LinkedListInit() {   
    function LinkedList() {
        this.head;
    }        
    return new LinkedList();
// ...

Comments

1

The only things accessible outside of the Node module are those added to the module.exports variable.

When you do

var x = require('./some/path');

x will be equal to the module.exports variable defined in ./some/path.js.

Unless Node is somehow made explicitly available in your module.exports object, you cannot access it from outside the module file.

The typical way to define modules with an IIFE in Node is to do:

module.exports = (function() {
    //...a lot of code...
    return { 
      exportedValue1: somethingIWantToBeAvailable;
      exportedValue2: aDifferentThing;
      //... and so on ...
    };
})();

But you don't really need the IIFE. Unlike a browser environment, stuff only gets added to the global scope in node if you explicitly request that by saying

global.variable = something;

Otherwise, your variable is in module-local scope. As Node treats modules and files as being in one-to-one correspondence, this means any variables you create within a file are only accessible within that file - barring the use of global and module.exports.

2 Comments

Note that this answer is highly Node.js specific -- depending on your runtime and build process, global may not be a thing.
Indeed, but the answer specified they were talking about the Node.js module system.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.