Node.js中仅模块的范围

时间:2014-04-23 19:47:34

标签: javascript node.js scope globals

我正在尝试使用函数在模块的顶级范围内设置变量,但不要将其泄漏到全局范围内(因为......坏)。起初我以为模块中的隐式变量声明会保留在模块中,但它似乎也适用于调用模块的脚本。

以示例(aModule.node.js)为例:

var
  onlyToThisModule = true;

function createAGlobal() {
  //creates a implicit var unfortunately
  globalToEveryone = true;
}

createAGlobal(); //this will now appear in the global scope for the script that require() it. eeek.

console.log(onlyToThisModule);

exports = createAGlobal;

然后要求它:

var
  aModule = require('./aModule.node.js');

console.log(globalToEveryone); //outputs "true"
console.log(typeof onlyToThisModule); //outputs "undefined"

我想要做的是在createAGlobal中声明一个不会泄漏到全局范围内的变量。我想将它保留在调用它的函数的范围内。我知道我可以把它放在模块本身的var语句中,但是我只想在有人执行该函数时声明变量。有没有办法实现这种类型的范围?

3 个答案:

答案 0 :(得分:1)

当您在不使用var的情况下定义变量时,它将被置于全局范围内,并且具有超出此注释范围的其他一些细微差别。它不是'隐含变量'。

无论如何,可以通过require()从任何地方访问模块本身,因此您不需要创建任何全局:

在aModule中

exports.globalToEveryone = true;

在另一个模块中

var globalVal = require('aModule').globalToEveryone;

扩展: 如果您想要控制对它的访问,那么您想要从任何地方访问的值几乎肯定不应该是全局的。对于您的目的,可能更好的答案是使用访问器方法:

var globalToEveryone = undefined;
exports.globalToEveryone() = function() {
    if (globalToEveryone !== undefined) {
        return globalToEveryone;
    } else {
        // what happens if it hasn't been set yet?
    }
}

当您对该值感兴趣时,在代码的其他地方,您将使用

var localVersion = require('aModule').globalToEveryone();

你会发现虽然你需要多输入一点才能得到这个值,你将拥有更多可维护的代码。

答案 1 :(得分:0)

为什么要求变量只有在有人调用函数时才会声明?如果这不是严格要求,那么您可以在模块范围内声明它,并在您的函数范围内初始化它:

var onlyToThisModule; // currently `undefined`

function initVar() {
    onlyToThisModule = true;
}

console.log(onlyToThisModule); // undefined
initVar();
console.log(onlyToThisModule); // true

...另一方面,如果你真的只想在函数中声明一个变量,但是它也可以用于模块的其余部分,那么你可以将它创建为一个类属性:

function myClass() {
    this.onlyToThisModule = true;
}

var mc = new myClass();
console.log(mc.onlyToThisModule);

...但是这仍然会通过函数的中介将变量暴露给调用模块。

如果这些都不适合您的情况,那么您将需要提供更多详细信息。

答案 2 :(得分:0)

好的。感谢您的回答尝试,但经过多次烦恼和研究后,I don't think it is possible完全按照我的要求去做,但我已经足够接近我的项目了。

死胡同:我能够使用V8的堆栈跟踪访问作用域链中的变量内容并伪造错误。我无法设法写入链中的范围。再加上这有些疯狂。我也试图做一些Object.defineProperty诡计,但我从来没有按照要求完全工作。

出于我的目的,它可以将所有内容放入一个对象中然后使用with,这比全局变量稍微不那么邪恶。对于我需要的情况,它工作正常。所以,像这样:

var local = { 
    a : '1',
    b : '2',
    c : '3'
};

function contained() {
    with (local) {
        console.log(a,b,c);
    }
}
console.log(typeof a) //undefined
contained();

现在我将只通过模块传递本地对象,并让脚本或其他模块在需要时使用with。不像我希望的那样语法纯粹。我还认为隐式变量应该只对模块本地化,因为你可以使用global.foo访问全局变量(我知道,不会发生,会打破互联网等等)