javascript中的圆括号()放置 - 不寻常的语法?

时间:2014-03-17 00:25:45

标签: javascript syntax

我遇到了以下代码 here

window.requestAnimFrame = (function(callback) {
    return window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame || 
    window.msRequestAnimationFrame ||
    function(callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();

现在我对javascript很新,我对语法有一些疑问。首先,MDN定义了requestAnimationFrame方法here,但在这个例子中,他们在最后没有()的情况下调用它,其次在最后一个分号之前似乎有一个额外的()。我不太理解两种情况下的推理,所以一些启示会非常有用!

提前感谢。

3 个答案:

答案 0 :(得分:2)

  1. 内部函数名称旁边没有括号,因为它们不是调用(已执行),它们只是引用。基本上,该函数检查以查看存在哪个函数,并return对它找到的第一个函数的引用。通过这种方式,您最终会在所有浏览器上引用该函数的可用版本。
  2. 末尾的额外括号 执行一个函数 - 匿名函数启动(function(callback) {并结束})。这被称为"IIFE",是一种在JS中将代码分组在一起的方式,具有自己的变量范围,但是立即计算答案。
  3. 最终结果是window.requestAnimFrame最终指向存在的任何函数或虚拟实现window.setTimeout(callback, 1000 / 60)

    该函数实际上并未被调用,但代码现在可以调用window.requestAnimFrame(something)而不用担心它不存在。

答案 1 :(得分:1)

这就是所谓的立即调用函数表达式(缩写为IIFE)。您可以阅读更多有关他们的信息here

简而言之,它是一个立即执行的函数定义,并且立即执行的返回值被赋给window.requestAnimFrame。这只是设置window.requestAnimFrame中的函数。 window.requestAnimFrame之后没有任何parens,因为此代码不执行该特定功能。它正在执行其他一些函数(因此为什么最后会有parens)并将该函数的结果赋给window.requestAnimFrame,这样当将来某个时候调用它时,它将调用相应的函数。

IIFE可以解释如下......

您将此语法知道为函数定义:

function() {
}

然后将其包含在一组额外的parens中,以便JS解释器将其视为一个表达式来进行评估:

(function() {
})

然后,为了使其执行该函数表达式,最后添加()来实现:

(function() {
})();

然后,在该函数的代码内部执行的是return语句,该语句将返回该立即执行的函数的结果,并将该返回值分配给window.requestAnimFrame。以简化形式,这是:

window.requestAnimFrame = (function() {
    return x;
})();

其中x原本是一个函数本身,是其他一些计算的结果。在这种情况下使用IIFE的主要优点是预先评估一些只运行一次的代码,这样window.requestAnimFrame只要被调用就会运行得更快。

IIFE最常见的用途是创建一个函数范围,以便从父或全局范围中隔离变量,而无需创建命名函数。

答案 2 :(得分:1)

实际上,这是一个非常有趣的函数调用嵌套。让我们从“最内在”的功能开始吧。看看它在做什么:

function(callback) {
    window.setTimeout(callback, 1000 / 60);
};

这是一个函数定义,它接受另一个函数作为参数。然后它会在超时时调用该函数。理解函数本身就是JavaScript中的对象,函数的这个定义本身就是一个对象,它将我们引向了下一个层次:

return window.requestAnimationFrame || 
       window.webkitRequestAnimationFrame || 
       window.mozRequestAnimationFrame ||
       window.oRequestAnimationFrame || 
       window.msRequestAnimationFrame ||
       function(callback) {
           window.setTimeout(callback, 1000 / 60);
       };

此代码返回一个函数对象。已经在window对象(它找到的第一个对象)上定义的那个,或者,如果没有别的话,它最后定义的那个。同样,函数是可以像变量一样传递的对象,这只是从函数返回一个值。该值本身恰好是一个函数,可以在以后执行。

整个结构都包含在自己的功能中:

function(callback) {
    return window.requestAnimationFrame || 
           window.webkitRequestAnimationFrame || 
           window.mozRequestAnimationFrame ||
           window.oRequestAnimationFrame || 
           window.msRequestAnimationFrame ||
           function(callback) {
               window.setTimeout(callback, 1000 / 60);
           };
}

所以这个函数返回一个函数。然后我们将整个事物包装在括号中并执行它:

(function(callback) {
    return window.requestAnimationFrame || 
           window.webkitRequestAnimationFrame || 
           window.mozRequestAnimationFrame ||
           window.oRequestAnimationFrame || 
           window.msRequestAnimationFrame ||
           function(callback) {
               window.setTimeout(callback, 1000 / 60);
           };
})()

所以现在返回函数的函数会在()之后执行。所以整个事物的价值就是一个功能。具体来说,这将评估内部函数返回的函数。然后,该函数作为值分配给变量:

window.requestAnimFrame = (function(callback) {
    return window.requestAnimationFrame || 
           window.webkitRequestAnimationFrame || 
           window.mozRequestAnimationFrame ||
           window.oRequestAnimationFrame || 
           window.msRequestAnimationFrame ||
           function(callback) {
               window.setTimeout(callback, 1000 / 60);
           };
})();

所以,总的来说,整个事情的作用是为window.requestAnimFrame分配一个函数。它是通过一些有趣的函数嵌套来实现的,但最终这就是它所做的一切。