【问题标题】:Should I use window.variable or var?我应该使用 window.variable 还是 var?
【发布时间】:2011-10-17 18:20:54
【问题描述】:

我们有很多设置 JS 代码来定义面板、按钮等,这些代码将在许多其他 JS 文件中使用。

通常,我们会这样做:

grid.js

var myGrid = .....

combos.js

var myCombo = .....

然后,在我们的应用程序代码中,我们:

application.js

function blah() {
    myGrid.someMethod()
}

someother.js

function foo() {
    myCombo.someMethod();
    myGrid.someMethod();
}

那么,我们应该使用var myGrid 还是使用window.myGrid 更好

有什么区别?

【问题讨论】:

    标签: javascript global-variables


    【解决方案1】:

    功能上一个潜在的重要区别是window.myGrid 可以是deleted,而var myGrid 不能。

    var test1 = 'value';
    window.test2 = 'value';
    
    
    console.log( delete window.test1 ); // false ( was not deleted )
    console.log( delete window.test2 ); // true  ( was deleted )
    
    
    console.log( test1 );  // 'value'         ( still accessible )
    console.log( test2 );  // ReferenceError  ( no longer exists )
    

    【讨论】:

    • 这是最好的答案,因为它实际上回答了问题。
    • "var" 似乎调用 Object.defineProperty 且可配置=false
    • 在属性描述符中,configurable:false 是唯一的区别。请参阅 (jsbin.com/zazuzi/edit?js,console) 现在,为什么会有这种差异?它似乎在这里得到了回答(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…),它说delete is only effective on an object's properties. It has no effect on variable or function names. 全局变量确实驻留在全局对象上的事实是一个“实现”细节,但声明变量的意图和特征通过可配置标志。
    【解决方案2】:

    我建议创建一个命名空间变量var App = {};

    App.myGrid = ...
    

    这样可以限制全局命名空间的污染。

    编辑:关于变量数量问题 - 想到 2 个可能的解决方案:

    1. 您可以通过类型(网格、按钮等)或关系(ClientInfoSection、AddressSection 等)进一步命名它们
    2. 您将方法封装在使用您拥有的组件实例化的对象中

    例如:你有

    function foo() {
        myCombo.someMethod();
        myGrid.someMethod();
    }
    

    变成:

    var Foo = function(combo, grid) {
        var myCombo = combo;//will be a private property
        this.myGrid = grid;//will be a public property
        this.foo = function() {//public method
            myCombo.someMethod();
            myGrid.someMethod();
        }
    }
    App.myFoo = new Foo(someCombo, someGrid);
    App.myFoo.foo();
    

    这样你可以限制小对象的数量并且只暴露你需要的(即 foo 函数)

    PS:如果你需要暴露内部组件,请在构造函数中将它们添加到 this 中

    【讨论】:

    • +1 这就是我的答案。这还具有创建一个唯一名称的好处,该名称将您的应用程序与其他人的应用程序区分开来。
    • 我喜欢这个主意。但是,如果我们在 App 全局中拥有数百甚至数千个 little objects (如按钮、数字字段等),这仍然可行吗?
    • @cbmeeks 没有人能阻止你进一步命名变量 App.Grids.myGrid 等
    • 所以......为了清楚起见(四年后),您的答案是var。所有这些关于命名空间的业务实际上都与这个问题无关。命名空间本身仍然是一个全局变量,必须使用一种方法或另一种方法创建。
    • @cbmeeks - 如果您有数千个(命名的)对象,那么将它们声明为诸如App 之类的主对象的一部分会更有价值。如果您不这样做,那么您就是将这数千个名称添加到“窗口”中——这将不再实用——它们总是附加到 something。
    【解决方案3】:

    window.variable 的一个很好的用途是您可以检查它而不会出现 javascript 错误。例如,如果您有:

    if (myVar) {
        //do work
    }
    

    并且myVar 没有在页面的任何地方定义,你会得到一个javascript 错误。然而:

    if (window.myVar) {
        //do work
    }
    

    不会出错,并且可以按预期工作。

    var myVar = 'test' 和 window.myVar = 'test' 大致相同。

    除此之外,正如其他人所说,您应该从一个全局对象下降以避免污染全局命名空间。

    【讨论】:

    • 值得一提的是,使用MyApp.myVar(请参阅已接受的答案)与window.myVar 具有相同的好处(只要在某处声明了MyApp)。 var App = {}; ... App.myVar = "whatever"; ... if (App.myVar) ... ... if (App.thisVarWasNeverDeclared) {...} - 没有错误,只是跳过该代码。测试是否从未声明:if (App.myVar === undefined) { App.myVar = "some default"; }.
    【解决方案4】:

    在全局范围内,两者实际上在功能方面是等效的。在函数范围内,当需要闭包的行为时,var 肯定是更可取的。

    我会一直使用var:首先,它与闭包中通常首选的行为一致(因此,如果您稍后决定将代码移动到闭包中更容易),其次,它说我正在创建一个变量而不是附加窗口的属性对我来说更具语义。但目前主要是风格。

    【讨论】:

    • 它们并不完全等同。 window 的属性可以使用delete 运算符删除,而使用var 声明的变量不能删除。此外,仅使用 var 的代码可移植到非浏览器环境。
    • 蒂姆:即使在全球范围内?这对我有用(至少在 Chrome 中):var x = 10; delete window.x;。后一个语句返回true,然后当我尝试引用x 时,我得到一个ReferenceError。不过,我还没有阅读规范,因此 V8 可能以这种方式不兼容。
    • 原来如此。我的立场是正确的;我应该更加小心地在 JavaScript 控制台中验证这样的边缘情况
    • @Tim Down +1 提醒我并非所有 JS 都会运行客户端。
    【解决方案5】:

    这个问题的一般答案是使用var。

    更具体地说,始终将您的代码放在Immediately Invoked Function Expression (IIFE):

    (function(){
      var foo,
          bar;
      ...code...
    })();
    

    这可以防止像 foo 和 bar 这样的变量污染全局命名空间。然后,当您明确希望将一个变量放在全局对象(通常是 window)上时,您可以编写:

    window.foo = foo;
    

    JavaScript 有函数作用域,充分利用它真的很好。你不会希望你的应用程序因为其他程序员做了一些愚蠢的事情而崩溃,比如覆盖了你的计时器句柄。

    【讨论】:

      【解决方案6】:

      除了其他答案,值得注意的是,如果您在声明变量时不在函数内使用var,它会泄漏自动进入全局范围,使其成为@987654322 的属性@对象(或全局范围)。

      【讨论】:

        【解决方案7】:

        要扩展 Liviu 所说的内容,请使用:

        App = (function() {
            var exports = {};
            /* code goes here, attach to exports to create Public API */
            return exports; 
        })();
        

        通过这样做,您可以隐藏一些特定于实现的代码,您可能不希望通过在内部使用var 来暴露这些代码。但是,您可以访问附加到 exports 对象的任何内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-24
          • 2018-09-05
          • 1970-01-01
          • 2015-10-16
          • 2023-03-06
          • 2013-02-20
          相关资源
          最近更新 更多