我听说过全局变量很糟糕,我应该使用哪种替代解决方案?

时间:2010-04-10 12:11:30

标签: javascript global-variables

我已经阅读了global variables are bad以及应该使用替代方案的地方。在Javascript中,我应该选择什么解决方案。

我正在考虑一个函数,当有两个参数(function globalVariables(Variable,Value))时,看看变量是否存在于本地数组中,是否确实将其值设置为Value,否则{{1}并且附加了Variable。如果在没有参数(Value)的情况下调用该函数,则返回该数组。也许如果仅使用一个参数(function globalVariables())触发函数,它将返回数组中function globalVariables(Variable)的值。

你怎么看?我想听听你使用全局变量的替代解决方案和论据。

您将如何使用Variable

globalVariables();

这是Singleton Pattern BTW吗?

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

谢谢,感谢您的帮助!

9 个答案:

答案 0 :(得分:127)

在javascript中不鼓励全局变量的主要原因是因为,在javascript中所有代码共享一个全局命名空间,javascript也隐含了全局变量,即。未在本地范围内显式声明的变量会自动添加到全局命名空间。过分依赖全局变量可能会导致同一页面上各种脚本之间发生冲突(阅读Douglas Crockford's articles)。

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

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的名称。

答案 1 :(得分:40)

语义学我的孩子。语义。

从一个全局开始: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/

答案 2 :(得分:9)

全球国家在几个方面造成问题。一个是代码重用。当您访问某个全局​​状态时,意味着组件必须知道它的环境(本身之外的东西)。你应该尽可能地避免这种情况,因为它会使组件变得不可预测。

假设我有一个访问globalVariables函数的对象,我想在另一个页面中使用它。我如何知道定义globalVariables对象甚至如何定义它?但是,如果您可以将信息传递给构造函数或作为函数的参数,那么我可以轻松确定对象所需的内容。

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

答案 3 :(得分:3)

你真的不想这样做。
至于为什么,请参见例如这里的帖子是:What is the most EVIL code you have ever seen in a production enterprise environment?

作为旁注,人们总是可以执行“全局”代码,而不会乱丢全局的地方:

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

答案 4 :(得分:3)

使用全局变量通常是一种不好的做法,无论选择何种语言。在strict mode时,它们甚至(轻松)都不允许使用,我强烈推荐。

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

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

我需要转过身来问一个felow程序员这个session变量来自哪里,因为没有代码搜索显示在哪里设置。

我发现公司的另一个包设置了全局变量。 编码就像一个笑话:如果你需要解释它可能不是那么好。

使用ES6的解决方法:

如果在Node,请使用importrequire将所需内容纳入词汇范围,不要让人们在您不知情的情况下触摸您的全球环境。

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

如果您在前端为浏览器提供代码,则除非您使用Babel转换ES6代码,否则无法使用import

使用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"
  }
};

答案 5 :(得分:2)

您的解决方案的问题在于它只会让您更难理解代码,同时仍然保留全局变量的所有缺点。您链接的页面涵盖了问题。您提出的解决方案真正解决的唯一问题是命名空间污染,但代价是无法像声明函数调用一样轻松地查看全局变量的声明。

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

答案 6 :(得分:1)

其他答案大多以匿名函数解释为this文章提及,

  

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

以下是具有正常功能的示例。它更容易阅读和理解。



/* 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




答案 7 :(得分:1)



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();




答案 8 :(得分:0)

全局变量很糟糕......如果不加管理!

全球变量的潜在风险与经常使用的物品随时可用的快乐和生产力增益一样高。

我不相信应该寻求一个替代方案。相反,我提倡一个负责管理这些全局变量的对象,并且随着代码库/组件的成熟,重构它们

我认为当前答案中没有提及的一件事是对DI和IoC容器的理解。这些解决了人们试图用全局变量解决的许多问题,但却涵盖了普通全局变量无法解决的相关问题,如对象生命周期。

相关问题