是否应避免全局变量

Should global variables be avoided?

本文关键字:全局变量 是否      更新时间:2023-09-26

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

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中不存在访问修饰符,所以应该避免全局变量吗?

您可能会使用此代码来代替

<!-- 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. width和height应该是this.widththis.height,否则您将修改全局width和height变量,这些值将不会绑定到Rectangle的单个实例
  2. 对于构造函数,最好使用函数表达式而不是函数声明:var Rectangle = function(w, h) { ... }而不是function Rectangle() { ... }
  3. 您还可以将所有代码封装在一个立即自执行的函数中,以完全避免全局名称空间污染(看看jAndy的答案)
  4. 对象的初始宽度和高度可以在构造函数中传递以进行初始化(否则,默认情况下,宽度和高度设置为0或其他任何值)
  5. 这些规则是明确编写的(请参阅D.Crockford的Javascript:好的部分)

这个不成文的规则仍然适用吗?

是的,您应该始终避免全局变量。我不知道为什么在您的代码中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中不存在访问修饰符,所以应该避免全局变量吗?

没有。无论编程语言如何,都应始终避免使用全局参数

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

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

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

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

尝试:

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

等等。。。

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

应避免使用全局变量。你应该把东西包起来。

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

通常在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变量的完整性。

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

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

    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,但为什么会这样呢?

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

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