是否应避免全局变量
Should global variables be avoided?
学习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);
- width和height应该是
this.width
和this.height
,否则您将修改全局width和height变量,这些值将不会绑定到Rectangle的单个实例 - 对于构造函数,最好使用函数表达式而不是函数声明:
var Rectangle = function(w, h) { ... }
而不是function Rectangle() { ... }
- 您还可以将所有代码封装在一个立即自执行的函数中,以完全避免全局名称空间污染(看看jAndy的答案)
- 对象的初始宽度和高度可以在构造函数中传递以进行初始化(否则,默认情况下,宽度和高度设置为0或其他任何值)
- 这些规则是明确编写的(请参阅D.Crockford的Javascript:好的部分)
这个不成文的规则仍然适用吗?
是的,您应该始终避免全局变量。我不知道为什么在您的代码中width
和height
是在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
}());
这种简单的模式完全避免了任何冲突。
要使其按预期运行,需要创建实例属性,而不是使用全局变量width
和height
。您当前的方法会导致多个Rectangle
实例使用相同的变量。
尝试:
function Rectangle () {
this.width = 0;
this.height = 0;
}
Rectangle.prototype.setWidth = function(w) {
this.width = w;
};
等等。。。
正如其他人所指出的,全局变量width
和height
将由当前作用域中的所有其他代码共享(注意: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;
}
}
无论如何,使用其他答案中所述的公共属性要容易得多,除非您真正关心width
和height
变量的完整性。
它更像是一个通用的编码标准。坦率地说,全局变量是邪恶的。
所以,假设您有以下代码。
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,但为什么会这样呢?
是的,它仍然是真的。您应该始终避免全局变量。
在您的示例中,width
和height
是全局的。如果这是完整的代码,那么问题就不大了。但是,如果你后来决定引入另一个"类",比如GameField
,该怎么办。它也有宽度和高度,自然。我闻到这里有麻烦。
- 在 Javascript 中创建全局变量时是否需要指定对象类型
- JSHint是否可以输出有关全局变量的警告
- 检查全局变量是否存在的正确方法是什么
- 确定是否在不使用任何全局变量的情况下加载了窗口
- js事件循环是否意味着可以为临时暂存空间使用全局变量
- 是否可以肯定刷新 $_SESSION[] 全局变量
- 如何在不设置全局变量的情况下确定是否已调用函数
- 对函数内部的全局变量所做的更改是否全局反映?Javascript
- 对角度模块使用单个全局变量是否是一种反模式
- 在 NodeJS 中使用和更新全局变量是否安全?
- 函数是否像局部变量一样适用于全局变量
- Javascript - 全局变量和全局范围内的变量是否不同(在 jsfiddle 中)
- 全局变量存储在 Node.JS 中的什么位置?节点中是否有类似窗口的对象
- 我是否正在创建一个全局变量
- 在Couchbase JavaScript视图中是否有可能的全局变量
- 是否可以将 Ext.Component 声明为全局变量
- 是否有任何选项可以在煎茶触摸中声明全局变量
- 自定义 jquery 函数中的参数是否可以更改全局变量的值
- 对于Javascript游戏引擎,重用全局变量是否比使用局部变量更有效?
- 在 .js 文件中声明全局变量是否不好