2012-02-12 129 views
1

我正在开发一个带有node.js和socket.io的应用程序。我已经在特定于连接的块中构建了一个包含一些变量和函数的小型项目。这些函数可以访问在该块中声明的变量,而不需要特别传递值。NodeJS函数/模块包含范围

这工作得很好,是这个规模的项目可以接受的。但是,当我试图清理代码时,我考虑将这些函数分解到它们自己的文件中,并找到使用exports.functionname声明的模块,如下所述:http://nodejs.org/docs/v0.3.2/api/modules.html

但是,这些函数没有访问同一块中的变量,正如它们在require()'d in时通常所做的那样,而不是在文件中实际声明。

有一些方法,使功能在外部文件的行为,就好像他们在本地的NodeJS声明?

回答

2

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

我不能说我推荐它的生产。基本上这个问题更多的是JavaScript本身。节点将模块包装在一个函数中,以便它们拥有自己的专用范围。在该范围内共享的唯一方法是在该功能内部执行,这对于模块(模块化...)系统来说不会起作用。唯一的其他范围是全球性的,这也是不可取的。

我用来解决这个问题的诀窍是改变这个包装函数,使其具有基于外部定义的模块导入集的动态属性,以便从模块包装器内部看到所有这些参数看起来像是神奇地定义的,但aren全球化。

节点的模块包裹器看起来是这样的:

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

凡矿只是增加了更多的参数,并确保他们在执行模块包裹器之前要解决。

我有它加载一个模块之前阅读给定文件夹命名为“.deps.json”文件。 一个例子一个会是这样

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

所以它会加载在这些子文件夹的模块,然后暴露每一个如在包装的参数,基于所述文件名命名。

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)); 
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作用域创建新的引用。

为此相互转换功能串和eval它。这将创建一个具有相同代码但具有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