正确调用Javascript匿名函数时';s声明,不';不行,以后再打会好的

正确调用Javascript匿名函数时';s声明,不';不行,以后再打会好的,javascript,html,canvas,requestanimationframe,Javascript,Html,Canvas,Requestanimationframe,[答] 我正在为html5游戏测试浏览器的fps。 我有以下代码: var requestAnimationFrame = ( function() { return window.requestAnimationFrame || //Chromium window.webkitRequestAnimationFrame || //Webkit window.mozRequestAnimationFrame || //Mozilla Geko window.oR

[答]

我正在为html5游戏测试浏览器的fps。
我有以下代码:

var requestAnimationFrame = ( function() {
    return window.requestAnimationFrame || //Chromium 
    window.webkitRequestAnimationFrame || //Webkit
    window.mozRequestAnimationFrame || //Mozilla Geko
    window.oRequestAnimationFrame || //Opera Presto
    window.msRequestAnimationFrame || //IE Trident?
    function(callback) { //Fallback function
        window.setTimeout(callback, 1000/60);
    }
})();

var hits = 0;
var last = new Date().getTime();

var step = (function(){
    now = new Date().getTime();
    hits += 1;
    if( now - last >= 1000 ){
        last += 1000;
        console.log( "fps: "+ hits );
        hits = 0;
    }
    requestAnimationFrame( step );
})();
在Chrome上出现以下错误:
未捕获错误:类型不匹配\u错误:DOM异常17

第27行:
requestAnimationFrame(步骤)

W3表示此错误为:
如果对象的类型与与与该对象关联的参数的预期类型不兼容。

但是,除了
窗口

但是如果我删除分配给
step
的匿名函数的调用括号,而只是声明该函数,并在新的一行输入:
step()

它起作用了。
这是为什么?

这两个函数不应该工作相同吗?

requestAnimationFrame
需要一个函数,但在代码中,
step
不是一个函数,它是未定义的,因为您不从自调用函数返回任何值

var step = (function(){
    // this code is executed immediately, 
    // the return value is assigned to `step` 
})();
如果删除调用括号,那么
步骤实际上是一个函数

var step = (function(){
    // this code is executed immediately, 
    // the return value is assigned to `step` 
})();

请参阅@Martin对该答案的评论。我指的是,执行函数后,
步骤
未定义的
,但是当您第一次调用函数时,它当然也是
未定义的。

我看到了几个问题。您正在为步骤指定匿名函数的返回值。然而,当删除括号时。您正在使步骤成为一个函数。由于您没有在匿名函数中返回值,
步骤
未定义的
。因此,您将得到一个类型错误。我会去掉结尾的括号。

我看到一些关于这里发生的事情的基本误解。例如,在您的第一次声明中:

var requestAnimationFrame = ( function() {
    return window.requestAnimationFrame || //Chromium 
    window.webkitRequestAnimationFrame || //Webkit
    window.mozRequestAnimationFrame || //Mozilla Geko
    window.oRequestAnimationFrame || //Opera Presto
    window.msRequestAnimationFrame || //IE Trident?
    function(callback) { //Fallback function
        window.setTimeout(callback, 1000/60);
    }
})();
您正在创建一个匿名函数,然后立即调用它并将结果分配给一个变量。我不明白这有什么意义。以下措施同样有效:

var requestAnimationFrame = 
    window.requestAnimationFrame || //Chromium 
    window.webkitRequestAnimationFrame || //Webkit
    window.mozRequestAnimationFrame || //Mozilla Geko
    window.oRequestAnimationFrame || //Opera Presto
    window.msRequestAnimationFrame || //IE Trident?
    function(callback) { //Fallback function
        window.setTimeout(callback, 1000/60);
    };
现在没有匿名函数(除了小的回退函数),它只是运行的代码。您可以对
step()
函数进行类似的简化。

其中的问题如下(已更正):

var step = (function(){
    // this code is executed immediately, 
    // the return value is assigned to `step` 
})();

您当前的代码本质上是“运行此匿名函数并将其返回值分配给
步骤
”。这有两个基本问题:

  • 该函数不返回值,因此即使在运行
    步骤之后
    也将未定义
  • 即使函数确实返回了一个值,您也会在函数第一次运行时尝试在函数内部使用
    步骤
    ,此时尚未对
    步骤
    进行赋值
  • 修复此问题的最简单方法是您已经执行的操作,即将
    步骤
    声明为函数,然后在下一行运行它:

    var step = function() { ... };
    step();
    
    也可以使用命名函数表达式:

    (function step() {
       ...
       requestAnimationFrame( step );
    })();
    
    这相当于:

    (function () {
        ...
        requestAnimationFrame( arguments.callee );
    })();
    
    不幸的是


    而且不幸的是(无论如何,从我的观点来看,这是不幸的)现在已经被弃用,无法在严格模式下工作。

    它似乎在FireFox中工作。运行时,FireBug显示
    mozRequestAnimationFrame()
    函数对象。编辑:再看一下你的代码,为什么你要在
    步骤
    的赋值中传递步骤?我认为这本质上是在引用构造函数中对象的实例。。。您所做的看起来有点像在的示例,但步骤更简单地被声明为一个函数…+1,即使步骤在被调用时没有定义,但在调用后它仍然没有定义,因为立即函数不返回任何内容。@Martin:对,我实际上是指这个问题,甚至没有注意到调用函数时它也是未定义的。谢谢谢谢现在很明显,但我没有看到。
    DOM
    错误分散了我的注意力。你是对的,这里不需要使用匿名函数。我假设代码是@FelixKling:Good catch的某个变体。复制粘贴编程规则!你说得对,我是复制粘贴的受害者,但你说的更有意义。你将
    步骤
    分配给函数的结果,而不是函数本身。我在这里的更正将函数分配到
    步骤
    。哦,对了,你的注释会比代码更好地解释它。谢谢