【问题标题】:javascript function as argument and scope variablesjavascript函数作为参数和范围变量
【发布时间】:2013-11-04 23:17:53
【问题描述】:

我有一个函数 - 让我们将它定义为 function getdata(after){},它以 after 参数作为函数。很自然。该函数正在从其他函数运行,该函数在其范围内定义了一些变量:

$('.button').click(function(){
   var rel = $(this).attr('rel');
   var mooo = $(this).parent().offset().left;
   getdata(function(){alert(rel);console.log(moo)});
});

我如何正确传递这些变量,所以它真的和点击按钮时一样吗?它不能是全局变量,因为用户可以垃圾邮件单击按钮,并且它应该在单击期间保持变量原样,即使 after 函数会在 10 分钟后以随机顺序被调用,因为正如名称所说 - 它在 ajax 请求之后被调用。

这只是一个例子 - 这个想法是这个 after 函数也是可变的,从完全不同的地方调用。


好的,收到-1,因为不清楚我在问什么,所以我试着解释一下这个问题。我真的不明白什么时候变量作为变量传递,什么时候作为变量的指针传递,变量的指针可能会在它被传递给的函数使用之前发生变化。

当我在一个函数中定义变量并将其传递给另一个函数时,它是指针还是独立变量?当我再次调用 origin 函数时,这些变量会改变 - 它会影响之前“shedled”的函数吗?或者变量之前的单词 var 意味着 - 将其定义为全新的变量,并且每次调用带有 var 的函数时,它都会将该变量作为全新的变量分配到内存中,不依赖于发生的任何事情?

我通常是一名 PHP、C 和 Delphi 程序员,我有点难以理解这些变量范围是如何工作的,尤其是当一切都是异步和回调时。

【问题讨论】:

  • 除非发送给函数的参数是一个对象,否则它将传递它的值而不是它的引用。当您发送一个字符串($(this).attr('rel') 属性)和一个整数($(this).offset().left)时,您无需担心 getdata 调用回调的可能延迟。回调中打印的变量将包含单击按钮时的值。
  • 如何确定它是作为字符串还是对象传递? $(this).offset() 是一个对象,$(this).offset().left 是独立字符串?如果我想传递 $(this) 发送者对象,以便能够在函数完成后更改对象?
  • @FlashThunder 查看我的更新答案。我不建议您使用它,但它可以让您深入了解变量范围和 JS 的动态特性。

标签: javascript jquery


【解决方案1】:

简单来说,在 javascript 中,简单类型(字符串、数字、布尔值)通过值传递,而对象通过引用传递。 see this question for a real detailed answer.

如果您不知道要处理多少个参数(或它们的类型),那么您可以使用arguments array

var getdata = function(){
    //your function logic

    //arguments is an array with all the args
    //the last one is the "after" function
    var after = arguments[arguments.length-1];
    return after(arguments);
};

$('.button').click(function(){
   var rel = $(this).attr('rel');
   var mooo = $(this).parent().offset().left;
   getdata(rel, moo, /*add all the arguments you want here...*/, function(args){
       alert(args[0]);
       console.log(args[1])
   });
});

【讨论】:

  • 但这些变量的类型和数量可能完全不同。
  • @FlashThunder 您无法从 JS 的作用域中预测所有变量。您必须指定哪些变量可用于非词法范围的函数,即外部函数的源代码中的字面意思。见stackoverflow.com/questions/1047454/what-is-lexical-scope
  • @FlashThunder 你能做的最好的就是传递一个对象,你可以添加任意数量的属性,无论你想要什么类型
  • @FlashThunder,您可以使用 arguments 数组来读取可变数量的参数,或者像 Juan Mendes 指出的对象。
【解决方案2】:

我不确定你在问什么,但这是 rvignacio 答案的变体,允许 getdataafter 使用任意数量的参数:

var getdata = function(after){
    //your function logic
    return after.apply(null, [].slice.call(arguments, 1));
};

$('.button').click(function(){
   var rel = $(this).attr('rel');
   var mooo = $(this).parent().offset().left;
   getdata(function(rel_param, moo_param){
       console.log(rel_param);
       console.log(moo_param)
   }, rel, moo);
});

【讨论】:

  • OP希望传入的函数可以使用相同的变量范围,这在JS中是不可能的,只有词法变量范围。
【解决方案3】:

您无法完全按照您的描述进行操作。您要做的是将所有关联的闭包传递给回调。在 JavaScript 中,使用了变量的词法范围。这意味着

function outer (callback) {
  var a = 1, b = 2, c = 3;
  var inner = function () {
     // This works because inner is defined inside of outer
     // and has access to a,b,c
     console.log(a,b,c); 
  }      
  inner();
  callback();
}

outer(function() {
    // This won't work because it doesn't know where to get a,b,c from
    // Some languages may(could/allow?) this, JS doesn't
    console.log(a,b,c);
});

因此,为了解决您的问题,您必须通过将它们作为参数传递来指定您希望哪些变量可用于回调。 rvignaciobfavaretto 已经向您展示了如何做到这一点

eval() 为胜利(真的为失败)

好的,有办法,但它需要eval,所以你不应该使用它。无论如何,这是为了好玩。 eval() 确实在同一范围内执行,因此通过在词法范围内添加一个 eval 和一个回调来调用它,您可以实现您想要的。同样,我不是建议你这样做。它破坏了封装,回调不应该知道调用者的隐私。但只是为了好玩……http://jsfiddle.net/zbwd7/1/

/**
 * The callback will accept a single argument, it's a function that takes the name
 * of the variable you want to use and returns its value. DON'T EVER DO THIS IN REAL CODE
 * @callback {function(string): *} getVar The function that gives you access to the
 * caller's scope
 * @callback.varName {string} The name of the variable to retrieve
 * @callback.return {*} The value of the variable
 */
function outer (callback) {
  var a = 1, b = 2, c = 3;

  function getVar(varName) {
      return eval(varName);
  }      
  callback(getVar);
}


outer(function(getVar) {
    // outputs one, two, three
    console.log(getVar("a"), getVar("b"), getVar("c") );
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多