将requestAnimationFrame分配给对象变量时出现类型错误

Type Error when assigning requestAnimationFrame to object variable

本文关键字:类型 错误 变量 requestAnimationFrame 分配 对象      更新时间:2023-09-26

当我试图创建对window.requestAnimationFrame的本地引用时,我遇到了这个奇怪的Type Error,它不断发生。以下工作正常,将记录Foo:

var foo = window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function(fn){ setTimeout(fn, 1000 / 24); };
foo(function(){ console.log('Foo') });

当我绑定到父对象时,但是,它不起作用并抛出Type Error,我不得不说这让我感到困惑:

var bar = {};
bar.foo = window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function(fn){ setTimeout(fn, 1000 / 24); };
bar.foo(function(){ console.log('Bar.Foo') });

即使windowwindow.requestAnimationFrame从来不是undefined,调用它们也会在嵌套时抛出类型错误。然而,当我比较这两个变量时,它们被认为是相等的。这有什么原因吗?是否有一种方法可以将工作引用撕成对象内部的正确实现?

document.body.innerHTML += 'About to call Foo: <br />';
try {
	var foo = window.requestAnimationFrame || 
		window.webkitRequestAnimationFrame || 
		window.mozRequestAnimationFrame || 
		window.msRequestAnimationFrame || 
		function(fn){ setTimeout(fn, 1000 / 24); };
		
	foo(function(){ document.body.innerHTML += '<i>Foo</i><br />'; });
} catch(e){
	document.body.innerHTML += '<i> &gt;&gt;&gt; Error thrown when calling Foo.</i><br />';
}
document.body.innerHTML += 'About to call Bar.Foo: <br />';
try {
	var bar = {};
	bar.foo = window.requestAnimationFrame || 
		window.webkitRequestAnimationFrame || 
		window.mozRequestAnimationFrame || 
		window.msRequestAnimationFrame || 
		function(fn){ setTimeout(fn, 1000 / 24); };
	bar.foo(function(){ document.body.innerHTML += '<i>Bar.Foo</i><br />'; });
} catch(e){
	document.body.innerHTML += '<i> &gt;&gt;&gt; Error thrown when calling Bar.Foo.</i><br />';
}
document.body.innerHTML += foo === bar.foo
  ? '<strong>Foo and Bar.Foo are considered the same</strong><br />'
  : '<strong>Foo and Bar.Foo are NOT considered the same</strong><br />';
body { 
  font-family: Monaco, 'Courier MS', Coureire, mono-space;
}

好吧,requestAnimationFrame是DOM API的一部分,它不是一个JavaScript对象,所以很难确定为什么它失败。请记住:

  • 函数在JavaScript中被this设置为调用对象,在你的情况下,对象是bar,它没有window所有的属性。
  • 默认对象JavaScript函数是用window分派的-所以调用window.alertalert是一样的(除了在严格模式下)。

所以,在幕后它完全有可能在某处使用this。再说一次,它是一个"宿主对象",所以一切都不确定。

下面是类似的"普通"JS代码,具有相同的行为。

window.msg = "Hello";
function foo(){
    if(this !== window) throw new TypeError("Illegal Invocation");   
    alert(this.msg);
}
foo(); // alerts hello, `this` is window
window.foo(); // alerts hello
var bar = {};
bar.foo = foo;
bar.foo(); // typeerror

一种解决方法是将其封装在匿名函数中或使用bind

试试这个

var bar = {};
bar.foo = (window.requestAnimationFrame && window.requestAnimationFrame.bind(window)) || 
    (window.webkitRequestAnimationFrame && window.webkitRequestAnimationFrame.bind(window)) || 
    (window.mozRequestAnimationFrame && window.mozRequestAnimationFrame.bind(window)) || 
    (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window)) || 
    function(fn){ setTimeout(fn, 1000 / 24); };
bar.foo(function(){ console.log('Bar.Foo') });

设置this的*requestAnimation到窗口对象

根据@poke的评论

var bar = {};
bar.foo = (window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function(fn){ setTimeout(fn, 1000 / 24); }).bind(window);
bar.foo(function(){ console.log('Bar.Foo') });