【问题标题】:What's the meaning of "()" in a function call?函数调用中的“()”是什么意思?
【发布时间】:2010-09-04 07:38:06
【问题描述】:

现在,我通常使用 () 调用一个函数(不需要参数),如下所示:

myFunction(); //there's empty parens

除了 jQuery 调用,我可以逃脱:

$('#foo').bind('click', myFunction); //no parens

很好。但最近我在 SO 上看到了这条评论here

“考虑使用setTimeout(monitor, 100); 而不是setTimeout('monitor()', 100);。Eval 是邪恶的:)”

哎呀!我们真的在这里eval()-ing 一个字符串吗?我想我并不真正理解“调用”函数的意义和含义。调用和引用函数的真正规则是什么?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    在 JavaScript 中,函数是一流的对象。这意味着您可以将函数作为参数传递给函数,或者将它们视为一般变量。

    假设我们正在讨论一个函数hello

    function hello() {
        alert('yo');
    }
    

    当我们简单地写

    hello
    

    我们指的是不执行其内容的函数。但是当我们在函数名后面加上括号()

    hello()
    

    那么我们实际上是在调用会在屏幕上提示“yo”的函数。

    jQuery 中的bind 方法接受事件类型(字符串)和函数作为其参数。在您的示例中,您将类型 - “click”和实际函数作为参数传递。

    你看过《盗梦空间》吗?考虑这个人为的例子,它可能会使事情更清楚。由于函数是 JavaScript 中的一等对象,我们可以在函数内部传递和返回函数。所以让我们创建一个函数,在调用时返回一个函数,并且返回的函数在调用时也返回另一个函数。

    function reality() {
        return function() {
            return function() {
                alert('in a Limbo');
            }
        };
    }
    

    这里reality是一个函数,reality()是一个函数,reality()()也是一个函数。然而reality()()() 不是一个函数,而只是undefined,因为我们没有从最里面的函数返回一个函数(我们没有返回任何东西)。

    所以对于 reality 函数示例,您可以将以下任何内容传递给 jQuery 的绑定。

    $('#foo').bind('click', reality);
    $('#foo').bind('click', reality());
    $('#foo').bind('click', reality()());
    

    【讨论】:

    • 是的,我现在保持着在所有 SO 答案中使用“函数”次数最多的记录 - 27。
    • +1 用于 Inception 参考(当然还有很好的解释)
    • var f = function(){ return f; } 为例如何?让你输入f()()()()()()()()()()()()()()()ad infinitum,超级酷。
    • @Avinash - 不需要将每个调用都包含在括号内。
    • 你的演讲内容非常丰富和详细,你提供的所有信息确实是正确的,但我不得不说这个问题的实际答案是错误的。我相信你错过了 'monitor()' 周围的单引号,表示这不是一个函数或函数调用的函数引用(就像你的 inception 示例一样),但正如问题所暗示的那样,它是一个字符串,它将是 eval -ed 稍后作为要运行的函数调用。
    【解决方案2】:

    您的 jQuery bind 示例类似于 setTimeout(monitor, 100);,您将函数对象的引用作为参数传递。

    应避免将字符串传递给 setTimeout/setInterval 方法,原因与在不必要时应避免使用 evalFunction 构造函数的原因相同。

    作为字符串传递的代码将被评估并在全局执行上下文中运行,这可能会给您带来“范围问题”,请考虑以下示例:

    // a global function
    var f = function () {
      alert('global');
    };
    
    (function () {
      // a local function
      var f = function() {
        alert('local');
      };
    
      setTimeout('f()', 100); // will alert "global"
      setTimeout(f, 100);     // will alert "local"
    })();
    

    上例中的第一个setTimeout 调用将执行全局f 函数,因为被评估的代码无法访问匿名函数的本地词法范围。

    如果您将函数对象的引用传递给 setTimeout 方法 - 就像在第二个 setTimeout 调用中一样 - 将执行您在当前范围内引用的完全相同的函数。

    【讨论】:

      【解决方案3】:

      您在 jQuery 示例中所做的事情与第二个 setTimeout 示例中不同 - 在您的代码中,您正在传递函数并绑定 click 事件。

      第一个setTimout例子中传入了monitor函数,可以直接调用,第二个例子中传入的是stingmonitor(),需要evaled。

      当传递一个函数时,你使用函数名。调用时需要使用()

      Eval 将调用传入的内容,因此成功的函数调用需要()

      【讨论】:

      • 所以评论有误?他真的应该通过setTimeout(monitor(), 100); //note the parens
      • @Isaac Lubow:不,代码是正确的——只是你在每段代码中做了不同的事情。这两个例子不一样。
      • 如果您希望monitor 在 100 毫秒后执行,那么您会执行 setTimeout(monitor(), 100); //note the parens? 吗?
      • @Issac Lubow - setTimeout(monitor(), 100); 将立即执行 monitor 函数。 setTimeout("monitor()", 100); 将在 100 毫秒后评估 monitor()。看到第二个例子中的"了吗?
      • @Isaac Lubow - 我的意思是在对setTimeout 的调用中简单地使用monitor()(没有")将立即调用该函数,然后它的返回值将得到传递给setTimeout
      【解决方案4】:

      首先,“()”不是函数名的一部分。 它是用于进行函数调用的语法。

      首先,您可以使用函数声明将函数绑定到标识符名称:

      function x() {
          return "blah";
      }
      

      ...或使用函数表达式:

      var x = function() {
          return "blah";
      };
      

      现在,只要你想运行这个函数,你就可以使用括号:

      x();
      

      setTimeout 函数接受函数的标识符和标识符,或字符串作为第一个参数...

      setTimeout(x, 1000);
      setTimeout("x()", 1000);
      

      如果你提供一个标识符,那么它将作为一个函数被调用。 如果您提供一个字符串,那么它将被评估(执行)。

      首选第一种方法(提供标识符)...

      【讨论】:

      • If you supply an identifier, then it will get called as a function. If you supply an string, than it will be evaluated (executed).你能解释一下区别吗?
      • @Isaac 如果您提供一个字符串,那么这个字符串将作为 JavaScript 代码执行。例如:setTimeout('x = 3;', 100)。如您所见,这里没有调用任何函数。字符串'x = 3;' 被评估为赋值表达式。另一方面,如果你提供一个标识符名称,那么这个名称必须指向一个函数对象(然后将被调用)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-17
      • 2015-09-25
      • 1970-01-01
      • 2020-11-24
      • 1970-01-01
      • 1970-01-01
      • 2022-04-18
      相关资源
      最近更新 更多