Javascript命名空间仅适用于var

时间:2012-09-24 19:04:43

标签: javascript variables namespaces scope var

我有以下代码:

(function(){
...
var n = n || {};
...
})(); 

这就是我想要的,设置n等于{},因为这是它第一次遇到并且将是未定义的。不幸的是,由于这在函数内部,n的范围仅限于函数,我无法在其他脚本中使用它。

我想将该行更改为n = n || {},但我收到错误:ReferenceError: n is not defined

将其更改为n = {}按预期工作;然而,这不是我想要的。当我不使用n并按预期工作时,我不明白var未定义导致错误的原因(用于获得正确方面的假值)当我做的时候,OR声明)根据我对var关键字的理解,我希望它既可以兼有,也可以不兼容。

为什么var很重要,这里发生了什么?

9 个答案:

答案 0 :(得分:3)

所以听起来你在创建全局变量时遇到了麻烦。

好。

在JavaScript中创建全局变量比应该更容易。

您的问题是n未定义(duh)。您无法引用尚未定义的变量。但你可能会想,“与使用var的版本有什么不同?”这是一个很好的问题。

JavaScript做了一个叫做“挂起”变量定义的东西。如果在函数中定义变量,则该定义将隐式重定位到函数的顶部。所以当你写道:

var n = n || {};

真正发生的事情更接近:

var n;
n = n || {};

然而,事情并非如此简单,因为如果您尝试编写该代码,最终会将n设置为{}。但一般的本质是存在的。变量声明在赋值之前发生。

如果删除var,则会导致引用错误,因为无法再提升声明。因此,一个“正确的”(我使用该术语松散,因为创建一个全局变量永远不是“正确的”)做你想要的方法就是把你的var放在你的函数包装器之外。像这样:

var n = n || {};
(function () {
    //do stuff.
}()); 

不幸的是,你不能这样做:

var n; 
(function () {
    n = n || {};
}());

与我上面的例子有同样的“问题”。如果n在其他位置定义,则undefined将其设置为var n;,然后在函数中设置为{}。通过在函数外部完成整个声明和赋值,您可以获得所需的内容。我假设(基于你的问题的标题)实际上是命名空间而不是一些任意的全局变量。那会很顽皮! ; - )

<强>更新

哦,顺便说一下,更好的方法是明确引用全局对象:

(function (exports) {
    exports.n = exports.n || {};
}(this));

对于像node.js这样的东西以及任何可能包含你的代码的东西(比如$(function() { })),这可能会更好。

答案 1 :(得分:2)

您遇到了未定义变量与具有未定义值的已定义变量之间的区别。

引用未定义的变量将导致异常(ReferenceError: n is not defined

引用具有未定义值的已定义变量很好,并且会在条件中强制转换为false

为避免这种情况,您可以将n作为window对象的属性引用,因为属性永远不会被定义,只有未定义的值。

(function(){
...
window.n = window.n || {};
...
})(); 

答案 2 :(得分:1)

n尚未宣布,因此检查n是否为真,将无效。您可以明确检查是否已声明n

n = typeof n !== 'undefined' ? n : {};

但是看起来不是很好。要在全局范围内放置某些内容,请使用window.n代替n或在您的函数之外声明n

var n;

(function(){
...
n = n || {};
...
})(); 

答案 3 :(得分:1)

1)小改变会有所帮助:

(function() {
    var n = window.n = window.n || {};
    // Code of your module...
    n.hello = function() {
        alert('Hello');
    };
})();

n.hello();

DEMO

通过这种方式,您可以n,全局可见,同一对象的本地参考n 在你的功能中。

2)我建议你以下一种方式重新设计它。

将每个模块设为:

var MyApplication = (function(app) {

    // Code of the module here...

    app.hello = function() {
        console.log('Hello!');
    };

    return app;
})(MyApplication || {});

MyApplication.hello();

答案 4 :(得分:0)

在函数结束时执行:

window.n = n;

这会将n放在全局命名空间中,允许您在其他脚本中使用它。

答案 5 :(得分:0)

使用严格模式,您需要显式使用全局命名空间,通常为window;更改使用window.n的行可以获得您想要的内容:

window.n = window.n || {};

答案 6 :(得分:0)

您可以在代码之前添加var n;,然后您将拥有全局nvar很重要,因为它使n成为函数的本地。

答案 7 :(得分:0)

var创建局部变量而不使用它会污染全局命名空间。浏览器应该阻止这种情况,因为大多数情况下你不想创建一个全局变量。

您可以使用window对象:

window.n = window.n || {}

但这只适用于浏览器环境。如果不是这种情况(例如,您正在使用服务器端JavaScript),那么以这种方式检索全局对象:

var global = (function getGlobal(){
    return (function(){
        return this;
    }).call(null);
}());

然后:

global.n = global.n || {};

答案 8 :(得分:0)

1)在第一轮评估中,var n = n || {};您正在创建变量:

var n = undefined;

2)在第二轮评估中,您有条件地设置值:

n = undefined || {};

3)没有var语句,你有一个var,它根本不存在,被引用

var myVar = non_existant_var; // error

如果var已经存在,比如说,在全局范围内,或者当前函数嵌套在其中的任何其他函数,它将使用它在链上的路上找到的n。如果不存在,它将适合。

所以不是故意在你的代码中挖洞,试图让代码知道你试图访问哪个范围,为什么不直接访问它?

(function (name) {
    window[name] = window[name] || {}; // returns undefined and not reference error
    var ns = window[name];

    ns.init = function () {};
    // .............
    /* Don't return the application to a var -- it already exists in the global scope */
}("BigLongApplicationName"));

BigLongApplicationName.init(); // === window.BigLongApplicationName.init();