如何在多个函数之间传递变量 - JavaScript/jQuery

3
这个问题的概括是如何在JavaScript函数之间传递变量,但不使用返回变量、在主要函数之间传递参数、使用全局变量或强制函数1等待函数2完成。我找到了一个jQuery解决方案并在下面发布了(在答案部分)。
旧帖子:我初始化了一组四个函数,每个函数以不同的方式调用彼此。最终,我需要将最终修改后的产品(一个数组)返回给初始化函数。
全局变量无法强制初始函数等待。反向返回四次也不起作用。如果不能返回它,你如何将修改后的变量传回其初始化函数?或者为什么它没有返回?
(迷宫从initFunctionA开始,在functionD结束)
classOne = {
  initFunctionA : function() {
    classTwo.functionB(functionD, array);
    // I NEED ACCESS TO ARRAY2 HERE
  },
  functionD : function(data, array) {
    var array2 = // modifications to array
  }
}

{...}

classTwo = {
  functionB : function(callback, array) {
    $.ajax({
      success: function(ret){
        classTwo.functionC(ret, callback, array)
      }
    });
  },
  functionC : function(ret, callback, array) {
     callback(ret.data.x, array);
  }
}

JavaScript数组是按引用传递的,所以如果你将同一个数组传递给嵌套函数,最后一次调用时你应该能得到修改后的数组。你能贴出完整可运行的代码吗? - axel_c
那段代码真的毫无意义;特别是 classTwo.function(functionB, array)。你是在说你要在那里调用 functionB 吗? - Pointy
@axel_c - 你说得对。抱歉。在我的最后一个函数中,我使用第一个数组创建了另一个数组(array2)。我试图在所有操作结束时只说array = array2,但它仍然不起作用。它返回修改之前的数据(initFunctionA继续执行而不等待)。代码真的很长。但我已经进行了编辑,希望现在更清楚了。谢谢你的帮助! - Kyle Cureau
@Pointy 是的,我在那里调用了 functionB 函数。 - Kyle Cureau
5个回答

1

我会使用对象构造函数:

function ClassOne() {
    this.array2 = [];
}

ClassOne.prototype.initFunctionA = function() {
    // ...
}

ClassOne.prototype.functionD = function(data, array) {
    // Can use array2 EX: this.array2
}

var classOne = new ClassOne();

我认为问题的关键在于异步Ajax调用,它并不真正与类的构建方式有任何关系(尽管我承认这有点难以确定)。 - Pointy
@Pointy,我明白为什么你感到困惑了。我把字母搞混了 :) 我已经修正了它们。@ChaosPandion...明天我会回来尝试你的解决方案。 - Kyle Cureau
+1 我从未测试过这个,因为我需要保持我的类静态和组织方式与项目的其余部分相同。它可能有效,也可能遇到Pointy提出的问题。我不够专业,无法确定。我用另一种方法解决了我的问题(我在下面发布了)...但是+1,因为这可能是一个完全有效的解决方案,看起来它可能正好做到你所说的。 - Kyle Cureau

1

更改您的回调函数(在调用站点)以便捕获functionD的返回值。然后,更改functionD,使其返回array2。我已经在下面的示例中添加了this访问作为方便。(此外,如果要使JSLint满意,请确保在“必需”处包含分号。)

classOne = {
  initFunctionA : function() {
    var self = this;

    classTwo.functionB(function() {
        var array2 = functionD.apply(self, arguments);

        // ACCESS ARRAY2 HERE
    }, array);
  },
  functionD : function(data, array) {
    var array2 = // modifications to array

    return array2;
  }
};

{...}

classTwo = {
  functionB : function(callback, array) {
    $.ajax({
      success: function(ret){
        classTwo.functionC(ret, callback, array)
      }
    });
  },
  functionC : function(ret, callback, array) {
     callback(ret.data.x, array);
  }
};

我尝试完全按照这个解决方案实现,但是我没有得到任何数据返回。虽然我也没有抛出任何错误,这很奇怪。我本来想进一步研究的,但我已经找到了一个可行的解决方案(我发布的那个)。话虽如此,你似乎知道你在说什么。我是个业余爱好者,不想搞砸堆栈溢出的MO,所以只要给我一个“是的,我有信心”,我就会接受这个答案。如果你有时间,请查看我的回应评论。谢谢! - Kyle Cureau
@Emile,你能发一下你的全部代码吗?你确定在functionD中返回了array2吗?你确定你编写的访问array2的代码在initFunctionA的匿名函数内部而不是外部吗? - strager
我确实尝试过,然后撤销了我的更改。请原谅我没有发布代码(我有期限,必须使用我的hacky解决方案)。但是...我从你的方法中学到了很多。我传递了array2以及其他几个参数,可能没有理解超过一个参数的微妙之处。话虽如此,+1和检查。我认为这肯定会帮助其他人。 - Kyle Cureau
据我理解,您是在说函数X内部的局部变量可以在所有由函数X调用的函数中使用,即使没有作为参数传递?(例如,在函数A中定义了self变量,然后调用函数B,在函数B的函数定义中引用了self,而在函数B的调用中并没有将self作为参数传递)我理解得对吗? - Euan M

1

你不能使用你写的那种模式使它工作;在Javascript中这是不可能的,因为没有所谓的“等待”。你的ajax代码必须带有一个回调参数(虽然不清楚它来自哪里或者它的作用),而且初始函数应该传入代码,在ajax调用完成后对数组执行需要的操作。


我想我找到了一种方法来模拟JavaScript中的“等待”,而不管ajax调用如何。它适用于我的目的,但我很欣赏您的意见。我在此答案部分发布了答案。 - Kyle Cureau

0
这是我理解你的问题的方式: classTwo 处理 AJAX 调用并可能修改结果。 classOne 使用 classTwo 获取一些数据并需要结果数据。
如果是这样,那么怎么样:
classOne = {
  initFunctionA : function() {
    var array = ['a','b','c'];
    classTwo.functionB(this.functionD, array);
  },
  functionD : function(data, array) {
    // This function is called when the AJAX returns.
    var array2 = // modifications to array
  }
}

{...}

classTwo = {
  functionB : function(callback, array) {
    $.ajax({
      success: function(ret){
        classTwo.functionC(ret, callback, array)
      }
    });
  },
  functionC : function(ret, callback, array) {
     callback(ret.data.x, array);
  }
}

所以classOne.initFunctionA调用classTwo.functionB来设置一个ajax调用。当ajax调用成功完成时,将使用结果和初始数组调用classTwo.functionC。从这里开始,将使用ret.data.x和数组调用classOne.functionD。


出色的理解函数顺序!我不确定我看到了解决方案。我需要在initFunctionA结束时使用array2。 - Kyle Cureau
你不能做那件事。解决方案是将依赖于array2的所有代码从initFunctionA移动到functionD中。它会像函数被分成两个部分,其中间有一个延迟(由ajax引起)。 - Matt
确实如@Matt所说。不过我刚找到了一个解决方案。已在下面发布。 - Kyle Cureau

0

好的!我找到了一种在不使用以下方式的情况下在函数之间传递变量的方法:

  • 创建全局变量
  • 创建对象属性(Chaos的解决方案)
  • 传递参数

这三种方法都被认为是唯一的方法。

不使用全局变量访问其他函数中的变量

但是,如果您无法直接传递参数,并且需要一个函数等待另一个函数(即不能依赖引用),并且您正在使用异步调用来自中间函数的服务器,则您唯一的解决方案是:

使用jQuery...

在DOM中创建此对象(如果您不想混淆标记,则动态创建):

<div id='#domJSHandler" style="display: none;"></div>

然后在必须等待的函数中:

//Function & Class Set 2
$('#domJSHandler').bind('proceedWithAction', function(event, param1, param2) {
    // action set 2
});

而在待等的函数中:

//Function & Class Set 1
// action set 1
$('#domJSHandler').triggerHandler('proceedWithAction', [param1, param2]);

基本上,将您需要执行的最后操作封装在一个jQuery绑定自定义事件中,并将其应用于不可见的DOM对象。使用jQuery的triggerHandler从JS触发该事件。传递参数,完成!

我相信SO会因为这个(以及自恋地接受我的答案)而批评我,但我认为对于一个超级新手来说,这非常棒,而且对我很有用。

所以:p Stack Overflow (jk 你们都曾多次拯救了我,我爱你们所有人:)


1
处理DOM就是处理全局状态。我认为这就是“创建全局变量”的意思,而不仅仅是使用JavaScript全局变量(即在浏览器中的window属性)。 - strager
全局变量作为控制函数顺序的解决方案(例如,在使用ajax时)的限制在于第二个(第三个,第四个)函数对变量执行其操作,而第一个函数继续执行。但从概念上讲,我同意你的观点。只是全局变量没有解决我的异步问题。这个方法可以。(虽然我刚看到了你的帖子,让我去看看) - Kyle Cureau
如果用户能够再次返回该页面,则在 .bind(...) 之前使用 .unbind()。 - Kyle Cureau
这与声明全局函数并从AJAX完成处理程序调用它没有任何区别。实际上,根本没有任何区别:DOM本身是全局的,因此绑定为事件处理程序的函数具有全局含义。您实现了一种间接级别,因为触发环境无需知道实际运行的函数,但通过拥有一个全局变量引用实际函数,效果完全相同。当然,直接调用全局函数比使用自定义事件更快。 - Pointy
如果我使用全局变量,我的第一个函数将不会“等待”运行。从ajax的成功中触发事件意味着被ajax调用的函数在完成之前不会触发,但是被调用的函数并不是我需要等待的函数。我感谢您的见解,但这两种方法对我产生了非常不同的结果。 - Kyle Cureau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接