我听说全局变量不好,我应该使用什么替代解决方案?

我已经阅读了所有的地方,全局变量不好和替代品应该使用。在 Javascript 中,我应该选择什么解决方案。

我想到的是一个函数,当提供两个参数(function globalVariables(Variable,Value))时,看看变量是否存在于一个本地数组中,如果它确实将其值设置为 Value,否则,将追加 VariableValue。如果函数调用时没有参数(function globalVariables()) ,它将返回数组。如果函数只用一个参数(function globalVariables(Variable))触发,那么它返回数组中 Variable的值。

你觉得怎么样? 我想听听你对使用全局变量的替代解决方案和论点。

如何使用 globalVariables();

function append(){
globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array.
};


function retrieve(){
var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1".
};


function retrieveAll(){
var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array.
};


function set(){
globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2".
};

顺便问一下,这是 单例模式吗?

在这个特定的场景中,一个函数可能在某个时间点设置一个变量,很久以后,另一个函数(可能是当用户提交表单时)将需要获取该变量。因此,第一个函数不能将变量作为参数传递给后面的函数,因为它永远不会从第一个函数调用。

谢谢,非常感谢你的帮助!

73674 次浏览

您的解决方案的问题在于,它只会使您的代码更难理解,同时仍然保留全局变量的所有缺点。您链接到的页面涵盖了这些问题。您提出的解决方案真正解决的唯一问题是名称空间污染,但代价是不能像声明是函数调用那样容易地看到声明了哪些全局变量)。

解决方案是编写没有全局变量的代码。如果一个函数需要一个值,将它作为参数传递给它。

你真的不想这么做。
至于为什么要看这篇文章,例如: 你在生产企业环境中见过的最邪恶的代码是什么?

值得注意的是,我们总是可以执行“全局”代码,而不会在这个地方乱丢全局代码:

(function() {
var notaglobal = 1;
alert(notaglobal);
})();
//notaglobal is not defined in this scope

全球化在几个领域引发了问题。一个是代码重用。当您访问某个全局状态时,这意味着组件必须知道它的环境(它自身之外的东西)。您应该尽可能避免这种情况,因为这会使组件变得不可预测。

假设我有一个访问 globalVariables 函数的对象,我想在另一个页面中使用它。我如何知道如何定义 globalVariables 对象,甚至如何定义它?然而,如果你可以将信息传递给构造函数或者作为函数的参数,那么我就可以很容易地确定对象需要什么。

此外,当您访问或修改全局范围时,您可能会影响其他对象。这就是为什么像 jquery 这样的库在全局范围内只使用一个名称(尽可能少)。它减少了与其他图书馆发生冲突的可能性。换句话说,全局作用域不在您的控制范围之内,因此它是危险的。

注意语义,孩子,注意语义。

从一个全局开始: myApp = {} ; 所有东西都应该在里面。唯一的例外是您的 AJAX 库(有一些极端的例外,比如使用 JSONP 回调)。

在 myApp 中应该只有很少的属性。您需要将应用程序属性保存在诸如配置或设置之类的容器中。

myApp = {
config:{
prop:1
},
settings:{
prop:2
},
widgets:{
List: function(props){},
Item: function(props){}
}
}

然后,您可能在较低的模块、组件、单例和类构造函数(小部件)中拥有更多的属性。

这种设置使您能够从任何其他位置访问任何属性,因为您可以通过 myApp 全局访问它。但是,您应该尽可能使用“ this”,因为查找速度更快。然后直接设置属性,不要使用伪 getter/setter。如果你真的需要一个 getter/setter,那就为这个特定的用途编写代码。

你的例子不起作用的原因是它太一般了,你似乎在寻找一个在全局空间工作的借口。

不要在私有变量上耍小聪明,它们也很糟糕: Http://clubajax.org/javascript-private-variables-are-evil/

在 javascript 中不鼓励使用全局变量的主要原因是,在 javascript 中,所有代码都共享一个全局名称空间,而且 javascript 还隐含了全局变量,即。未在本地范围中显式声明的变量将自动添加到全局命名空间。过多地依赖全局变量可能导致同一页上不同脚本之间的冲突(请阅读 道格拉斯·克罗克福特的文章)。

减少全局变量的一种方法是使用 YUI 模块模式。基本思想是将所有代码封装在一个函数中,该函数返回一个对象,该对象包含需要在模块外访问的函数,并将返回值赋给单个全局变量。

var FOO = (function() {
var my_var = 10; //shared variable available only inside your module


function bar() { // this function not available outside your module
alert(my_var); // this function can access my_var
}


return {
a_func: function() {
alert(my_var); // this function can access my_var
},
b_func: function() {
alert(my_var); // this function can also access my_var
}
};


})();

现在要在其他地方使用模块中的函数,请使用 FOO.a_func()。这种解决全局命名空间冲突的方法只需更改 FOO的名称即可。

无论选择哪种语言,使用全局变量通常都是不好的做法。他们甚至不(容易)允许使用时,在 严格模式,我强烈推荐。

考虑一下我找到的这段代码:

if (typeof session != 'undefined' && !data.cart.request_status)
data.input_definitions.passengers =
inflate_passenger(session, data.input_definitions.passengers);

我需要转过身去问一个程序员,这个 session变量是从哪里来的,因为没有代码搜索出现在设置的地方。

我从另一个包中找到了公司设置的全局变量。 代码就像一个笑话: 如果你需要解释,它可能没有那么好。

使用 ES6的解决方案:

如果在 Node,使用 importrequire将想要的东西带入词法范围,不要让人们在你不知道的情况下接触你的全局环境。

import {Sesssion} from 'api-core';
const Session = require('api-core').session;

如果你在浏览器的前端交付代码,你不能使用 import,除非你使用 巴别塔翻译你的 ES6代码。

使用 Gulp.js 进行传输的示例:

// $ npm install --save-dev gulp-babel babel-preset-es2015


// gulpfile.js
const gulp  = require('gulp');
const babel = require('gulp-babel');


gulp.task('transpile', () => {
return gulp.src('src/app.js')
.pipe(babel({presets: ['es2015']}))
.pipe(gulp.dest('dist'));
});


// $ gulp transpile

遗留问题解决方案:

当使用 ES6特性不是一个选项时,使用一大堆全局变量的唯一解决方案是只使用一个,并且有希望:

// scripts/app.js
var MyApp = {
globals: {
foo: "bar",
fizz: "buzz"
}
};

其他答案大多如 这个文章所述用匿名函数解释,

匿名函数很难调试、维护、测试或重用。

下面是一些函数正常的例子,比较容易阅读和理解。

/* global variable example */


var a= 3, b= 6;
    

function fwithglobal(){
console.log(a, b); // 3 6 expected
}
    

fwithglobal(); // first call
    

function swithglobal(){
var a=9;
console.log(a, b); // not 3 6 but 9 6
}
    

swithglobal(); // second call
    



/* global variable alternative(function parameter) */


function altern(){
var a= 3, b= 6; // var keyword needed
f_func(a,b);
s_func(a,b);
}
    

function f_func(n, m){
console.log(n, m); // 3 6 expected
}
    

function s_func(n, m){
var a=9;
console.log(n, m); // 3 6 expected
}
    

altern(); // only once

全局变量是坏的... 如果不管理!

全局变量的潜在风险与经常使用的对象随时可以使用带来的愉悦感和生产力收益一样高。

我不认为一个人应该只有一个选择。相反,我主张由一个对象负责管理这些全局变量,并且随着代码基/组件的成熟,将它们重构出来

当前的答案中没有提到的一件事情,我认为是至关重要的,那就是对 DI 和 IoC 容器的理解。它们解决了人们试图用全局变量解决的许多问题,但是涵盖了普通全局变量不能解决的相关问题,比如对象生命周期。

var ASHIVA_HandsOffNHS = (function() {
    

// VARIABLES


var my_var = 10;




// PRIVATE FUNCTIONS
    

function bar() {
window.alert(my_var + 5);
}




// PUBLIC OBJECT


myObject = {};
    

myObject['a_func'] = function() {
my_var += 10;
window.alert(my_var);
};
        

myObject['b_func'] = function() {
my_var = 0;
window.alert(my_var);
};


return myObject;


})();


ASHIVA_HandsOffNHS.a_func();
ASHIVA_HandsOffNHS.b_func();
ASHIVA_HandsOffNHS.a_func();