【问题标题】:Should global variables be avoided?应该避免全局变量吗?
【发布时间】:2012-02-25 07:09:24
【问题描述】:

学习 Javascript 并有一个关于全局变量的问题。根据我的阅读,大多数人建议不要使用它们。但是,在基于类的 javascripting 中,这条不成文的规则是否仍然适用?例如:

var width = 0;
var height = 0;

<!-- constructor -->
function Rectangle(){}

<!-- getters/setters -->
Rectangle.prototype.getWidth = function(){
    return width;   
}

Rectangle.prototype.setWidth = function(w){
    width = w;  
}

Rectangle.prototype.getHeight = function(){
    return height;  
}

Rectangle.prototype.setHeight = function(h){
    height = h; 
}

<!-- methods -->
Rectangle.prototype.area = function(){
    return height * width;  
}

var myRect = new Rectangle();
myRect.setWidth(5);
myRect.setHeight(4);
console.log(myRect.area()); //20
console.log(myRect.getWidth()); //5
myRect.setWidth(10);
console.log(myRect.getWidth()); //10
console.log(myRect.area()); //40

我熟悉 Java 以及对类、属性和方法使用访问修饰符的能力。是不是因为 Javascript 中不存在访问修饰符,所以应该避免使用全局变量?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    您可能会改用此​​代码

    <!-- constructor -->
    var Rectangle = function(w, h) {
        this.width = w || 0;
        this.height = h || 0;
    }
    
    <!-- getters/setters -->
    Rectangle.prototype.getWidth  = function( ) { return this.width;  }
    Rectangle.prototype.setWidth  = function(w) { this.width = w;    }
    Rectangle.prototype.getHeight = function()  { return this.height;      }
    Rectangle.prototype.setHeight = function(h) { this.height = h;    }
    
    <!-- methods -->
    Rectangle.prototype.area = function(){
        return this.height * this.width;  
    }
    
    var myRect = new Rectangle(5, 4);
    console.log(myRect.area()); //20
    console.log(myRect.getWidth()); //5
    myRect.setWidth(10);
    
    1. 宽度和高度应为this.widththis.height,否则您将修改全局宽度和高度变量,并且这些值不会绑定到 Rectangle 的单个实例。
    2. 最好使用函数表达式而不是构造函数的函数声明:var Rectangle = function(w, h) { ... } 而不是 function Rectangle() { ... }
    3. 您还可以将所有代码包装在一个立即自行执行的函数中,从而完全避免全局命名空间污染(查看 jAndy 答案)
    4. 可以在构造函数中传递对象的初始宽度和高度以进行初始化(否则宽度和高度默认设置为 0 - 或其他任何值)。
    5. 这些规则肯定是编写的(请参阅 D.Crockford 的 Javascript : the good parts 以供参考)。

    【讨论】:

    • this.width = w || 0; - 这是 OR 运算符的一个有趣用法。如果未设置 w,这将返回 0,我是否正确?
    【解决方案2】:

    这条不成文的规定还适用吗?

    是的,您应该始终避免使用全局变量。我不知道为什么 widthheight 在您的代码中声明在 Rectangle 之外。你需要大量使用this

    function Rectangle(h, w) {
        this.height = h || 0;
        this.width = w || 0;
    }
    
    <!-- getters/setters -->
    Rectangle.prototype.getWidth = function(){
        return this.width;   
    }
    
    Rectangle.prototype.setWidth = function(w){
        this.width = w;  
    }
    
    Rectangle.prototype.getHeight = function(){
        return this.height;  
    }
    
    Rectangle.prototype.setHeight = function(h){
        this.height = h; 
    }
    
    <!-- methods -->
    Rectangle.prototype.area = function(){
        return this.height * this.width;  
    }
    

    是不是因为 Javascript 中不存在访问修饰符,所以应该避免使用全局变量?

    没有。无论使用何种编程语言,都应始终避免使用全局变量。

    【讨论】:

    • 尝试在没有全局变量的 BASIC 中编程 :-)
    • 让我阻止你“尝试用 BASIC 编程”。我会过去的
    【解决方案3】:

    不惜一切代价避免使用全局变量的简单原因是,您永远无法确定同时加载了哪些其他脚本。因此,为了避免可能最终导致真正丑陋的错误场景的冲突,您至少应该将自己的代码包装到一个 closured 函数上下文中。

    (function() {
        // all of your code here
    }());
    

    这种简单的模式完全避免了任何冲突。

    【讨论】:

    • 除非所有Rectangle 实例都具有相同的维度,否则这不是删除全局变量的正确方法。
    【解决方案4】:

    要使其按预期运行,您需要创建实例属性,而不是使用全局变量 widthheight。您当前的方法会导致多个 Rectangle 实例使用相同的变量。

    试试:

    function Rectangle () {
      this.width = 0;
      this.height = 0;
    }
    
    Rectangle.prototype.setWidth = function(w) {
      this.width = w;
    };
    

    等等……

    正如其他人所指出的,全局变量 widthheight 将由当前范围内的所有其他代码共享(注意。JavaScript 只有函数级范围,而不是块级)。

    【讨论】:

      【解决方案5】:

      应该避免使用全局变量。你应该用闭包包装东西。

      仅在您想要公开功能时使用全局变量。

      【讨论】:

        【解决方案6】:

        通常在 OO JavaScript 中,您使用类定义创建一个闭包以避免污染全局范围。

        var Rectangle;
        
        (function() {
          var width = 0;
          var height = 0;
        
          Rectangle = function (){}
          ...
        
        })();  // the () execute the function with the closure
        

        这样你就可以定义私有属性并且仍然有一个干净的全局空间:)

        此外,为了防止评论中描述的 MДΓΓ БДLL 问题,同时仍然保留私有属性和 getter/setter,这是要走的路

        function Rectangle() {
          // Private properties
          var width = 0,
              height = 0;
        
          // Public methods using private properties
          this.setWidth = function(value) {
            width = value;
          }
        
          this.setHeight = function(value) {
            height = value;
          }
        }
        

        无论如何,使用其他答案中所述的公共属性要容易得多,除非您真的关心 widthheight 变量的完整性。

        【讨论】:

        • 除非所有 Rectangle 实例都具有相同的维度,否则这不是删除全局变量的正确方法。
        【解决方案7】:

        它更像是一个通用的编码标准。坦率地说,全局变量是邪恶的。

        所以,假设您有以下代码。

            var width = 10;
            
            <!-- constructor -->
            function Rectangle(){}
            
            <!-- getters/setters -->
            Rectangle.prototype.getWidth = function(){
                return width;   
            }
            
            Rectangle.prototype.setWidth = function(w){
                width = w;  
            }
        
            var myRect = new Rectangle();
            console.log(myRect.getWidth());
        

        嗯,这将完全符合您的预期,将 10 输出到控制台。

        但是,现在假设一个开发人员稍后进来,并在构造 myRect 和 console.log 之间添加了一条新行,例如:

        width=width * 10;
        

        现在,console.log 将返回 100。好吧,你说,这还不错。我仍然可以阅读。

        但是让我们将最后两行修改为:

        var myRect = new Rectangle();
        doSomethingCool();
        console.log(myRect.getWidth());
        
        function doSomethingCool() {
           LOTS o code;
           width = "10px"; // I need this to update the style sheet.
           LOTS o code;
        }
        

        突然之间,弄清楚实际发生的事情变得更加困难。

        肯定console.log会输出10px,但是为什么会这样呢?

        【讨论】:

          【解决方案8】:

          是的,它仍然是真的。您应该始终避免使用全局变量。

          在您的示例中,widthheight 是全局的。如果这是完整的代码,那就不是什么大问题了。但是,如果您稍后决定引入另一个名为 GameField 的“类”怎么办。它自然也有宽度和高度。我在这里闻到了麻烦。

          【讨论】:

            猜你喜欢
            • 2012-12-19
            • 1970-01-01
            • 1970-01-01
            • 2019-04-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-19
            • 2012-02-02
            相关资源
            最近更新 更多