javascript,将 requestAnimationFrame 和 cancelAnimationFrame 分配给对象的属性

javascript, assigning requestAnimationFrame & cancelAnimationFrame to properties of an object

//
// version 1
//
var requestAnimFram = (function(){
    return window.requestAnimationFrame    ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequsetAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        }
})();

//version 1 usage
function main(){
    //main loop
    ...
    requestAnimFram(main);
}
main();

//
// version 2
//
var animFram = {
    req: window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        },
    ccl: window.cancelAnimationFrame ||
        window.mozCancelAnimationFrame,
    myReq: 0
};

//version 2 usage
function main(){
    ...
    aniFram.myReq = aniFram.req(main);
}
main();

function stop(){
    aniFram.ccl(myReq);
}

在探索一些示例代码时,我发现了 requestAnimationFrame。版本 1 是从中雕刻出来的,它工作正常。找了一会儿,我也找到了cancelAnimationFrame,想两个都用。所以我制作了一个虚拟页面进行测试。版本2是从它雕刻出来的。

问题是,它没有循环。所以,我有两个问题。

  1. 这样用requestAnimationFrame不就不行了吗?如果是,为什么会这样?

  2. 如果可能的话-但我做错了,我该如何实现?

这是一个副本("Uncaught TypeError: Illegal invocation" in Chrome)。但我还是会更详细地回答我自己的问题,这样可以帮助其他人以不同的方式理解这件事。

  1. Is it impossible to use requestAnimationFrame in this way? If so, why exactly so?

不可能。

  1. If it's possible-but I'm doing it in wrong way, how can I acheive this?

这个问题本身可以通过使用 call()bind() 以及 apply() 方法轻松解决。

//Using call()
//Attach call method during invocation
aniFram.req.call(window, main);

//Using bind()
//Attach bind method during the object initialization
aniFram = {
    req: requestAnimationFrame.bind(window)
    ...
}
aniFram.req(main);

//Using apply()
//Attach apply method during invocation
aniFram.req.apply(window, [main]);

请注意这里的相似之处,即所有 3 种方法都有一个额外的参数 'window'。它们都有相同的原因:requestAnimationFramewindow 对象的方法,需要 window.

的上下文

aniFram 是一个对象。它有一个引用 window.requestAnimationFrame 的方法 reqaniFram.req(main)aniFram 的上下文中调用 window.requestAnimationFrame,而不是 window。这就是为什么它不起作用。让我们考虑另一个示例代码:

示例代码

var obj1 = {
    target: 'Jake',
    hitman: function(){
        this.target = 'RIP';
    }
};
var obj2 = {
    //assigns obj1.hitman to obj2.hitman
    hitman: obj1.hitman
};  
obj2.hitman();
console.log(obj1.target); //outputs 'Jake'

/////////////////////////////////////////
//call() method
obj2.hitman.call(obj1);
console.log(obj1.target); //outputs 'RIP'

//apply() method
obj2.hitman.apply(obj1);
console.log(obj1.target); //outputs 'RIP'

//bind() method
var obj2 = {
    hitman: obj1.hitman.bind(obj1)
};
obj2.hitman();
console.log(obj1.target); //outputs 'RIP'

这与您的代码版本 2 的情况完全相同。您调用引用 obj1.hitmanobj2.hitman() 希望更改 obj1.target 的值,但它什么也没做。因为 obj1.hitman 所做的是执行一条语句 this.target = 'RIP'。由于是在obj2的上下文中执行的,所以这条语句就变成了obj2.target = 'RIP'。 obj2.

中没有target属性

调用、申请、绑定

这就是这些方法发挥作用的地方。如果没有它们,Javascript 引擎会自动确定上下文(当前对象。即 aniFram、obj2)。通过将这些方法附加到您的代码,现在您可以决定在哪个上下文中执行它(即 window, obj1)。


这也称为别名函数。 (If Javascript has first-class functions, why doesn't this work?)