【问题标题】:Understanding Javascript scope with modules使用模块理解 Javascript 范围
【发布时间】:2017-03-30 18:11:55
【问题描述】:

我正在尝试了解范围如何与节点模块一起使用。我有一个 IIFE 来初始化一个 LinkedList,它为每个元素使用 Node 对象。
使用 IIFE 来避免污染全局范围

IIFE 之后,Node 去哪儿了?有什么方法可以访问需要对象中的节点,即测试类?

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?

【问题讨论】:

  • 你想做什么?

标签: javascript node.js module


【解决方案1】:

通常,在您的 ES6 模块中定义的任何函数和变量都是模块范围的,即在这种情况下您的 IIFE 不是必需的。 Nodeinsert 将无法从模块外部访问,除非它们通过 module.exports 显式导出。


考虑到这一点,单元测试也不能简单地访问实现细节。如果您想单独测试Node,最简洁的方法可能是将其移至单独的模块并将其导入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');
// ...

【讨论】:

  • 感谢@timo,您实际上帮助我改进了使用 module.exports 的方式。我曾经做过 module.exports = new LinkedList()。现在我觉得我一直都做错了。
【解决方案2】:

您的范围已包含在模块中 - 除了您选择导出的内容,因此您并不需要 IIFE。

如果您希望它与 IIFE 一起使用,您必须将 IIFE 附加到 module.exports,而不是将您的 IIFE 包裹在它周围。比如……

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

【讨论】:

    【解决方案3】:

    Node 模块之外唯一可访问的内容是添加到 module.exports 变量中的内容。

    当你这样做时

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

    x 将等于./some/path.js 中定义的module.exports 变量。

    除非Node 在您的module.exports 对象中以某种方式显式可用,否则您无法从模块文件外部访问它。

    在 Node 中使用 IIFE 定义模块的典型方法是:

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

    但你并不真的需要 IIFE。与浏览器环境不同,只有当您明确通过说

    请求时,才会将内容添加到节点中的全局范围中
    global.variable = something;
    

    否则,您的变量在 module-local 范围内。由于 Node 将模块和文件视为一一对应,这意味着您在文件中创建的任何变量只能在该文件中访问 - 除非使用 globalmodule.exports

    【讨论】:

    • 请注意,这个答案是高度特定于 Node.js 的——取决于您的运行时和构建过程,global 可能不是问题。
    • 确实,但答案表明他们在谈论 Node.js 模块系统。
    猜你喜欢
    • 2012-09-04
    • 2011-11-10
    • 1970-01-01
    • 2014-01-20
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    相关资源
    最近更新 更多