【问题标题】:Inject node module variable to scope将节点模块变量注入范围
【发布时间】:2015-12-26 04:18:27
【问题描述】:

是否可以使用节点模块来实现此行为?

module.js:

module.exports = function () {
    var test.fn = function () {
        console.log("$test.fn()");
    }

    var test.fn2 = function () {
        console.log("$test.fn2()");
    }

    var variable = "test";
};

app.js:

require("./module.js")();

test.fn();
test.fn2();
otherFunction(variable);

我不想做这样的事情$ = require("./module.js")(); $.test.fn(); 我想在没有包装变量的情况下将此变量注入 app.js 范围。

编辑:

我最终使用了这个:

module.js:

module.exports = function () {
    eval(String(inject));

    var inject = (
        this.$module1 = {},
        this.$module1.fn = function () {
            console.log("$module1.fn()");
        }
        );
};

app.js:

require("./module.js")();

$module1.fn();

【问题讨论】:

    标签: javascript node.js scope node-modules


    【解决方案1】:

    模块中的顶级作用域实际上是一个函数作用域(node.js 加载器将每个模块包装在一个函数中,然后调用该函数来执行模块中的代码)。因此,没有公开可用的“根”对象可供我们以编程方式为其分配属性。

    因此,这意味着如果不使用 eval() 在相当大的 hack 中,就不可能在模块中以编程方式在模块范围的顶层添加新变量。函数作用域在 Javascript 中不能这样工作。

    您还可以让模块将内容分配给global 对象,在该对象中可以不带前缀使用它们,但这绝不是推荐的做法。 node.js 模块的重点是避免使用任何全局变量,并使代码完全自包含,几乎没有全局冲突的机会。

    或者,您可以让您的模块导出一个巨大的 Javascript 字符串,然后在 app.js 中将 eval() 导出,以便在模块范围内定义新变量。再次 - 不推荐。

    最好的方法是按照“node.js 方式”做事,并将所有内容放在一个对象上并导出该对象。这是一种变体:

    app.js

    var test = require("./module.js")();
    
    test.fn();                  // "executing fn"
    test.fn2();                 // "executing fn2"
    console.log(test.myVar);    // "test"
    

    模块.js

    module.exports = function () {
        return {
           fn: function () {
               console.log("executing fn");
           },
           fn2: function() {
                console.loog("executing fn2");
           },
           myVar: "test"
        }
    };
    

    【讨论】:

    • 正如我所说,这正是我不想实现的。有没有其他方法可以将变量注入作用域?
    • @ddl - 我回答了你的问题,除非你想以相当老套的方式使用带有字符串的eval(),否则你不能这样做。我在回答中详细解释了为什么你不能用普通的 Javascript 来做到这一点。
    • @ddl - 如果你想用 eval() 来做,那么让你的模块导出一个巨大的 Javascript 字符串,让你的 app.js 从模块中获取该字符串,然后 eval() 将它放入 app .js。我不建议这样做。 node.js 中的模块架构导致moduleName.method() 成为最常见的设计模式,大多数 node.js 开发人员都已经习惯了。如果你真的想要一个捷径,你可以将模块变量分配给你自己的局部变量,但你不能用eval()自动地做到这一点。
    • @ddl - 感觉就像您只是想避免为模块中的内容输入moduleName.method()。这就是“node.js 方式”,出于许多正当原因,它是这样做的。如果您想编写可与他人共享的健壮、可重用的 node.js 代码,我建议您学习并使用常见的 node.js 设计模式,即使它们一开始感觉有些不同或有些尴尬。它的工作方式背后有逻辑。
    • 我知道我想做一件疯狂的事情,但我已经找到了一种方法,感谢您的反馈module.exports = function () { eval(String(( this.$fn = function () { console.log("$test.fn()"); } )); };
    【解决方案2】:

    您可以使用 IIFE 执行类似的操作。该方法会在需要时自动运行并返回一个对象,然后您可以在应用程序中使用该对象。

    module.js:

    global.test = (function() {
      return {
        fn: function() {
          console.log("executing fn");
        },
        fn2: function() {
          console.log("executing fn2");
        },
        variable: "test"
      }
    })();
    

    app.js

    require("./module.js"); //just include, no need for a wrapper variable
    test.fn();
    test.fn2();
    console.log(test.variable);
    

    请注意,如果全局变量 test 已经存在,此技术将覆盖它。

    【讨论】:

      【解决方案3】:

      这个答案不应该鼓励你在你的 node.js 模块中使用global(参见上面的 jfriend00 的 cmets),因为它会使你的代码容易与其他模块发生名称冲突,从而导致你的模块的可移植性降低。强>

      在 module.js 中,您可以访问 node.js 运行时环境的 global 对象。

      module.js:

      global.test = {
          fn: function() {
              //Do something
          },
          fn2: function() {
              //Do something different
          },
          variable: "test variable"
      }
      

      app.js

      require("./module.js"); //just include, no need for a wrapper variable
      test.fn();
      test.fn2();
      console.log(test.variable);
      

      请注意,如果全局变量 test 已经存在,此技术将覆盖它。

      【讨论】:

      • 皱眉。在 node.js 中使用全局变量,只是为了节省一点打字不是推荐的做法。
      • 同意这一点,我只是想展示这种可能性,因为@ddl 明确要求一种使模块对象在全局范围内可用的方法。
      • 实际上,OP 要求的是“app.js 范围”,而不是全局范围。它们不一样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 2011-05-05
      • 2018-06-04
      • 2012-01-27
      • 2019-09-10
      • 1970-01-01
      相关资源
      最近更新 更多