【问题标题】:javascript, assigning requestAnimationFrame & cancelAnimationFrame to properties of an object [duplicate]javascript,将requestAnimationFrame和cancelAnimationFrame分配给对象的属性[重复]
【发布时间】:2017-11-30 05:00:25
【问题描述】:
//
// 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. 如果有可能——但我做错了,我怎么能做到这一点?

【问题讨论】:

  • 您的模块中有语法错误:ccl: ccl, myReq: 0; // Remove semicolon
  • "除非我尝试扭曲它,否则它工作正常。" - 请告诉我们你是如何尝试扭曲它的。
  • 1) 可以编辑问题以使其变得更好,但请确保不要将其更改为完全不同的问题,尤其是在已经有答案的情况下。 2) 您可以通过单击 (X) 删除自己的 cmets,您可以将我的 cmets 标记为“已过时”,但我自己删除它们会更容易。
  • @Nathan P. 请您删除您的评论好吗?谢谢。
  • @Bergi 一切都完成了 :)

标签: javascript this requestanimationframe native-methods


【解决方案1】:

这是重复的 ("Uncaught TypeError: Illegal invocation" in Chrome)。但我仍然会更详细地回答我自己的问题,因为这样可以帮助其他人以不同的方式理解这个问题。

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

这是不可能的。

  1. 如果有可能——但我做错了,我怎么能做到这一点?

这个问题本身可以通过使用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 种方法都有一个附加参数“窗口”。它们都有一个相同的原因:requestAnimationFramewindow 对象的方法,需要 window 的上下文。

aniFram 是一个对象。它有一个方法req,它引用了window.requestAnimationFrameaniFram.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)。通过将这些方法附加到您的代码中,您现在可以决定在哪个上下文中执行它(即窗口、obj1)。


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

【讨论】:

    猜你喜欢
    • 2016-02-03
    • 2015-01-04
    • 2019-03-20
    • 2016-01-15
    • 2023-03-29
    • 2014-04-05
    • 2021-01-01
    • 2014-01-16
    相关资源
    最近更新 更多