NodeJS函数/模块包含范围

时间:2012-02-12 23:47:02

标签: node.js socket.io

我正在使用node.js和socket.io开发一个应用程序。我在一个特定于连接的块中构建了一个包含一些变量和函数的小型项目。这些函数可以访问在该块中声明的变量,而无需专门传递值。

这种方法很好,并且对于这种大小的项目是可以接受的。但是,当我尝试清理代码时,我考虑将这些函数分解到自己的文件中,并找到使用exports.functionname声明的模块,如下所述:http://nodejs.org/docs/v0.3.2/api/modules.html

但是,这些函数无法访问同一块中的变量,因为它们通常在执行require()时而不是实际在文件中声明。

是否有某种方法可以使外部文件中的函数表现得就像在nodejs中声明它们一样?

3 个答案:

答案 0 :(得分:2)

没有黑客攻击模块系统,这正是我所做的。 https://github.com/Benvie/Node.js-Ultra-REPL/blob/master/lib/ScopedModule.js

我不能说我推荐它用于制作。基本上问题在于JavaScript本身。 Node将模块包装在一个函数中,因此它们有自己的私有范围。共享该范围的唯一方法是在该函数内执行,该函数对模块(模块化...)系统不起作用。唯一的另一个范围是全球范围,这也是不可取的。

我用得到它周围是改变这种包装功能,具有基于外部定义的一组模块导入的动态属性,以便从模块包装内的所有这些参数看起来像他们奇迹般地定义,但大家还不诀窍t global。

Node的模块包装器如下所示:

(function (exports, module, require, __filename, __dirname){
  /**module**/
})

我只需添加更多参数,并确保在执行模块包装之前解析它们。

我在加载模块之前读取了给定文件夹中名为“.deps.json”的文件。 一个例子就是这个

[{
    "providers": [ "./utility/",
                   "./settings/" ],
    "receivers": [ "*" ]
}]

因此它会将模块加载到这些子文件夹中,然后将每个模块作为参数暴露在包装器中,并根据文件名命名。

答案 1 :(得分:1)

通常和干净的方法是在模块中定义一个函数,它将所需的变量作为参数:

// extracted_file.js
exports.handler = function(param1, param2) {
  return param1 + param2;
}

// caller file
var extractedHandler = require('./extracted_file').handle;

var localVar1 = 1300,
    localVar2 = 37;
console.log(extractedHandler(localVar1, localVar2));

答案 2 :(得分:0)

您可以使用toString()和可怕的eval更改功能范围。

如果您的函数在lib.js中如下: -

var lib = {}
lib.foo = function() { console.log(var1) }
lib.bar = function() { console.log(var2) }
module.exports = lib

在main.js中你可以这样: -

var var1 = 1
var var2 = 2
var ob1 = require('./lib')
ob1.foo()  
ob1.bar() 

当你运行它时,ob1.foo()行给出了一个ReferenceError,没有定义var1。这是因为foo()的范围来自lib.js而不是你的主js文件,而var1对它是不可见的。 ob1.foo是对具有lib.js作用域的函数的引用。您需要使用main.js范围创建一个新引用。

要执行此操作,请将每个函数转换为字符串并对其进行评估。这将创建一个具有相同代码但具有main.js范围的新函数。这是使用setMainScope方法的一种方法,该方法遍历所有将其范围更改为main.js的函数。

var var1 = 1
var var2 = 2
var ob1 = {}

ob1.setMainScope = function(ob2) {
for(var prop in ob2) {
    if( !ob2.hasOwnProperty(prop) ) {continue}
    if( typeof ob2[prop] !== 'function' ) {continue}
    this[prop] = eval( "(" + ob2[prop].toString() + ")" )
}
}

ob1.setMainScope( require('./lib') )
ob1.foo()  // 1
ob1.bar()  // 2

现在除了eval之外,一切都很顺利。 foo()bar()的范围现在为main.js,因此他们“看到”var1var2