从其他函数访问变量而不使用全局变量


71

我从很多地方都听说过,全局变量本来就是讨厌和邪恶的,但是当使用一些非面向对象的Javascript时,我看不到如何避免它们。假设我有一个函数,该函数使用复杂的算法使用随机数和填充物来生成数字,但是我需要在其他函数中继续使用该特定数,该函数是回调函数或其他东西,因此不能成为同一函数的一部分。

如果最初生成的数字是局部变量,则无法从那里访问它。如果函数是对象方法,我可以将数字设为属性,但是它们不是属性,并且更改整个程序结构来执行此操作似乎有些复杂。全局变量真的那么糟糕吗?


6
@annakata,因为SO上有很多滞留用户
vimes1984

Answers:


56

要使在函数A中计算出的变量在函数B中可见,您可以选择三种方法:

  • 使其成为全球性的
  • 使其成为对象属性,或
  • 从A调用B时将其作为参数传递。

如果您的程序很小,那么全局变量还不错。否则,我会考虑使用第三种方法:

function A()
{
    var rand_num = calculate_random_number();
    B(rand_num);
}

function B(r)
{
    use_rand_num(r);
}

4
不要污染全局名称空间!最糟糕的情况是,仅使用单个自定义全局对象创建对象属性
annakata

当这三个都不适合我时,我想到了第四个选择。 stackoverflow.com/questions/3531080/… (请参阅Emile的回答)
凯尔(Kyle

ps。在上面的链接上的pm,寻找“ Emile”的未经检查的答案
Kyle 2010年

我知道这已经很老了,但是我只是想知道,在大型程序中大量使用第三种方法会不会导致意大利面条式代码的产生?
Aryan poonacha

所以这很烦吗?一直试图解决这个问题,这是一个非常简单的示例
Pixelomo

81

我认为您最好的选择是定义一个 单一的全球范围的变量,并且有倾倒的变量:

var MyApp = {}; // Globally scoped object

function foo(){
    MyApp.color = 'green';
}

function bar(){
    alert(MyApp.color); // Alerts 'green'
} 

做上述事情的人都不会对你大喊大叫。


您的示例的问题在于,JavaScript处理嵌套对象需要更长的时间。(这将花费很长时间:MyApp.something.color.somethingElse
Progo

20
Progo,这不是真正的问题。
Triptych 2015年

6
该功能var()应该更改为bar(),这个微小的语法错误可能会让某些人头痛。
哈里·普约尔斯(Harrypujols),2015年

1
谢谢,正是我所需要的!但是我不明白,MyApp.color如果foo()从未调用过,应该如何创建和填充呢?
Chazy Chaz

三联,感谢有利于我的工作安全性:对
吉恩-迈克尔Celerier

15

考虑使用名称空间:

(function() {
    var local_var = 'foo';
    global_var = 'bar'; // this.global_var and window.global_var also work

    function local_function() {}
    global_function = function() {};
})();

双方local_functionglobal_function可以访问所有本地和全局变量。

编辑:另一种常见模式:

var ns = (function() {
    // local stuff
    function foo() {}
    function bar() {}
    function baz() {} // this one stays invisible

    // stuff visible in namespace object
    return {
        foo : foo,
        bar : bar
    };
})();

return编辑性能现在可以通过命名空间对象,如访问ns.foo,同时仍保留访问本地定义。


超级棒的答案!最后是一个类似其他语言的类结构:)
Dadan

太好了,这应该是公认的答案。第二种模式显然称为“使用对象模式进行静态命名
间隔

8

您要查找的内容在技术上称为currying。

function getMyCallback(randomValue)
{
    return function(otherParam)
    {
        return randomValue * otherParam //or whatever it is you are doing.
    }

}

var myCallback = getMyCallBack(getRand())

alert(myCallBack(1));
alert(myCallBack(2));

上面的函数并不是一个严格的函数,但是它实现了在不向全局名称空间添加变量或不需要其他对象存储库的情况下保持现有值的结果。


-1。这不仅不是欺骗的例子,而且对问题的答案也太复杂了。
三联画

5
@triptych:我不同意。这是对这类问题的一种非常有效和有趣的解决方案,并准确地柯里(dustindiaz.com/javascript-curry
annakata

+1令人困惑...然后启迪!一旦我清楚地看到,它myCallbackgetMyCallbackrandomValue已返回的函数的引用。使用也是getRand有启发性的,因为我看到myCallBack(1)多次调用将返回相同的值,因此myCallback等于从中返回的内容,getMyCallBack(getRand())而不仅仅是对函数本身的引用。它帮助只是把它大声说:)
wunth

5

我发现这对于原始问题非常有帮助:

返回要在functionOne中使用的值,然后在functionTwo中调用functionOne,然后将结果放入一个新的var中,并在functionTwo中引用此新var。这应该使您能够使用functionTwo中在functionOne中声明的var。

function functionOne() {
  var variableThree = 3;
  return variableThree;
}

function functionTwo() {
  var variableOne = 1;
  var var3 = functionOne();

  var result = var3 - variableOne;

  console.log(variableOne);
  console.log(var3);
  console.log('functional result: ' + result);
}

functionTwo();

4

如果另一个函数需要使用变量,则将其作为参数传递给该函数。

同样,全局变量并不是天生的讨厌和邪恶。只要正确使用它们,它们就没有问题。


2
全局变量在Javascript中极其有害。-1。
三联画

2

如果您有机会重用此代码,那么我可能会努力从面向对象的角度出发。使用全局名称空间可能很危险-由于变量名被重用,因此存在难以发现错误的风险。通常,我从使用面向对象的方法开始,而不是简单的回调,这样我就不必做重写的事情。我想,只要您在javascript中拥有一组相关功能,它都是面向对象方法的候选人。


2

另一种方法是我从Douglas Crockford论坛帖子(http://bytes.com/topic/javascript/answers/512361-array-objects)中获得的。这里是...

道格拉斯·克罗克福德写道:

2006年7月15日

“如果要通过id检索对象,则应该使用对象,而不是数组。由于函数也是对象,因此可以将成员存储在函数本身中。”

function objFacility(id, name, adr, city, state, zip) {

    return objFacility[id] = {

        id: id,
        name: name,
        adr: adr,
        city: city,
        state: state,
        zip: zip

    }
}

objFacility('wlevine', 'Levine', '23 Skid Row', 'Springfield', 'Il', 10010);

“对象可以通过”获得

objFacility.wlevine

现在可以从任何其他函数中访问对象属性。


1

我不知道您的问题的详细信息,但是如果函数需要该值,那么它可以是通过调用传递的参数。

全局变量被认为是不好的,因为全局变量状态和多个修饰符会产生难以遵循的代码和奇怪的错误。对许多演员来说,摆弄某些东西会造成混乱。


1

您可以使用自定义jQuery事件完全控制javascript函数的执行(并在它们之间传递变量)..有人告诉我,在所有这些论坛上都不可能做到这一点,但是我确实做了一些工作来做到这一点(即使使用ajax调用)。

这是答案(重要:这不是经过检查的答案,而是我“ Emile”的答案):

如何获取跨多个函数返回的变量-Javascript / jQuery

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.