在声明它时调用Javascript匿名函数不起作用,稍后再调用它

时间:2011-12-21 00:01:23

标签: javascript html html5 canvas requestanimationframe

[回答]

我正在测试我的浏览器的fps以获得html5游戏 我有这段代码:

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上出现以下错误:
Uncaught Error: TYPE_MISMATCH_ERR: DOM Exception 17
在第27行:requestAnimationFrame( step );

W3说这个错误是:If the type of an object is incompatible with the expected type of the parameter associated to the object.
但我实际上并没有与DOM进行交互,除了window

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

有效。
这是为什么? 两者都不应该一样吗?

5 个答案:

答案 0 :(得分:9)

requestAnimationFrame需要一个函数,但在您的代码中,step不是函数,它是undefined,因为您不会从自调用函数返回任何值。< / p>

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

如果删除了调用括号,那么step确实是一个函数。

请参阅@ Martin对此答案的评论。我指的是{/ 1}}在执行函数后step 这一事实,但当你第一次调用函数时它当然也是undefined 。。

答案 1 :(得分:2)

我看到对这里发生的事情有一些根本性的误解。例如,在您的第一个声明中:

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()函数应用类似的简化。

答案 2 :(得分:2)

问题包括(更正):

var step = function(){
    now = new Date().getTime();
    hits += 1;
    if( now - last >= 1000 ){
        last += 1000;
        console.log( "fps: "+ hits );
        hits = 0;
    }
    requestAnimationFrame( step );
};

答案 3 :(得分:1)

我看到了几个问题。您正在为步骤指定匿名函数的返回值。然而,当您删除括号时。你正在做一个功能。由于您未在匿名函数中返回值,stepundefined。因此,您将收到类型错误。我会在最后删除括号。

答案 4 :(得分:1)

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

  1. 该函数不返回值,因此即使在运行step之后也不会定义。
  2. 即使该函数确实返回了一个值,您也是在第一次运行时尝试在函数内部使用step ,此时step的赋值已经尚未发生。
  3. 解决这个问题的最简单方法就是你已经做过的事情,即将step声明为函数,然后在下一行运行它:

    var step = function() { ... };
    step();
    

    或者您可以使用命名函数表达式:

    (function step() {
       ...
       requestAnimationFrame( step );
    })();
    

    相当于:

    (function () {
        ...
        requestAnimationFrame( arguments.callee );
    })();
    

    不幸的是IE isn't that great at named function expressions

    而且不幸的是(不幸的是,从我的观点来看,不管怎样)arguments.callee现已弃用,并且无法在严格模式下运行。