在声明时立即调用 Javascript 匿名函数是行不通的,稍后调用它才可以

发布于 12-22 08:36 字数 1148 浏览 4 评论 0原文

[已回答]

我正在测试 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 上出现以下错误:
未捕获错误:TYPE_MISMATCH_ERR:DOM 异常 17
第 #27 行:requestAnimationFrame(step );

W3 表示此错误是:如果对象的类型与与该对象关联的参数的预期类型不兼容。
但我实际上根本没有与 DOM 交互,除了 window

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

它有效。
这是为什么?
两者不应该工作相同吗?

[answered]

I'm testing my browser's fps for an html5 game.
I have this code:

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 );
})();

It gives the following error on Chrome:
Uncaught Error: TYPE_MISMATCH_ERR: DOM Exception 17
On line #27: requestAnimationFrame( step );

W3 says this error is: If the type of an object is incompatible with the expected type of the parameter associated to the object.
But I'm not actually interacting with the DOM at all, except for window

But if I remove the calling parentheses of the anonymous function assigned to step and instead just declare that function and on a new line I put:
step();

It works.
Why is this?
Shouldn't both work the same?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

最笨的告白2024-12-29 08:36:13

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

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

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

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

requestAnimationFrame expects a function, but in your code, step is not a function, it is undefined because you don't return any value from your self-invoking function.

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

If you remove the calling parenthesis, then step is indeed a function.

Please see @Martin's comment to this answer. I was referring to the fact that step is undefined after the function is executed, but of course it is also undefined when you invoke the function the first time.

失而复得2024-12-29 08:36:13

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

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

I see some fundamental misunderstanding of what's going on here. For example, in your first declaration:

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);
    }
})();

You're creating an anonymous function, then immediately calling it and assigning the result to a variable. I don't see the point of this. The following would work equally well:

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);
    };

There's no anonymous function now (well except for the little fallback function), it's just code that runs. You can apply a similar simplification to your step() function.

站稳脚跟2024-12-29 08:36:13

其中的问题是(已更正):

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

Among the issues is this (corrected):

var step = function(){
    now = new Date().getTime();
    hits += 1;
    if( now - last >= 1000 ){
        last += 1000;
        console.log( "fps: "+ hits );
        hits = 0;
    }
    requestAnimationFrame( step );
};
别靠近我心2024-12-29 08:36:13

我看到几个问题。您正在为步骤分配匿名函数的返回值。然而,当您删除括号时。您正在将步骤设为函数。由于您没有在匿名函数中返回值,因此 stepundefined。因此,您将收到类型错误。我会删除最后的括号。

I see a couple of issues. You are assigning step the return value of the anonymous function. Whereas, when you remove the parentheses. You are making step a function. Since you are not returning a value in the anonymous function, step is undefined. Therefore, you will get a type error. I would remove the parentheses at the end.

烟织青萝梦2024-12-29 08:36:13

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

  1. 该函数不返回值,因此即使在运行之后 step 也将是未定义的。
  2. 即使函数确实返回了一个值,您也会在第一次运行时尝试在函数内部使用 step ,此时会分配给 step 尚未发生。

解决此问题的最简单方法就是您已经执行的操作,即,将 step 声明为函数,然后在下一行运行它:

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

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

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

这相当于:

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

不幸的是 IE 不太擅长命名函数表达式

而且不幸的是(无论如何,从我的角度来看,不幸的是) arguments .callee 现已弃用,并且无法在严格模式下工作。

Your current code essentially says "run this anonymous function and assign its return value to step". There are two basic problems with this:

  1. The function doesn't return a value, so even after it runs step will be undefined.
  2. Even if the function did return a value, you are trying to use step inside the function the first time it runs, at which point the assignment to step has not yet taken place.

The simplest way to fix this is what you already did, i.e., declare step as a function and then run it on the next line:

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

Or you could use a named function expression:

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

Which is the equivalent of:

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

Unfortunately IE isn't that great at named function expressions.

And also unfortunately (unfortunate from my point of view, anyway) arguments.callee is now deprecated and won't work in strict mode.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文