了解 .bind() 与参数的关系
Understanding .bind() in relation to arguments
我正在审查一些游戏代码,但我有一段不太明白。
var game = (function(){
// Start with our constructor
function Game(){
this.viewport = document.getElementById('viewport');
this.ctx = this.viewport.getContext('2d');
};
Game.prototype.updateAnimation = function(t){
// work out the delta time
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
// run relevent updates here
// queue the next animation time.
this.animationId = window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
}
// return game class
return Game;
})();
然后
// call new game object
var clientGame = new game();
// call event loop
clientGame.updateAnimation(new Date().getTime());
当请求 window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
运行时。它如何知道参数 t
的值。好像每次都会更新,但我不明白为什么。有人可以解释发生了什么事吗?谢谢。
编辑
Number
原型链上附加了一个名为 fixed()
的函数。这是为了清楚起见
Number.prototype.fixed = function(n) { n = n || 3; return parseFloat(this.toFixed(n)); };
首先代码可以写的更好,不需要每次都重新绑定函数,一次就够了(比如在对象初始化的时候)
其次,函数requestAnimationFrame
只接受一个参数,所以第二个参数没有意义,第一个参数是浏览器发送给回调的t
。
方法 .bind
不会更改函数参数(可能 arguments.callee
除外,尽管这是多余的)但仅更改函数的 context
因此第一个参数保持 t
(timestamp
)
更多信息https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
编辑
所以用户正在使用一些允许向 requestAnimationFrame 发送两个参数的 polyfill
所以requestAnimationFrame
有一个参数,一个回调函数,它获取时间戳作为参数。
绑定函数 returns 原始函数但在不同的范围内。因此 requestAnimationFrame
使用时间戳调用 updateAnimation,这是您的时间来源。
现在要了解 bind
调用背后的原因,您需要了解 JavaScript 中的范围。
当您定义一个函数并将其作为参数传递给另一个函数时,您实际上是在第二个函数的范围内调用第一个函数。这意味着如果你有一个 class 实例并且你想将一个实例方法作为回调传递给一个函数,你要么需要使用一个箭头函数来保留当前范围,要么你将方法绑定到正确的范围(你的 class实例)。
我希望下面的例子能更好地说明我在说什么。
class OuterScope {
constructor() {
this.label = 'test';
}
print() {
console.log(this.label);
}
}
function innerScope(callback) {
callback();
}
var scope = new OuterScope();
innerScope(scope.print); // throws error because the scope the function is called in doesn't have a property called label
innerScope(scope.print.bind(scope)); // prints label
现在将此应用于您的 requestAnimationFrame
问题:
class Game {
updateAnimation(t) {
// this.lastFrameTime would always be undefined when called without binding
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
window.requestAnimationFrame(this.updateAnimation.bind(this)); // updateAnimation now always runs in the scope of the current Game instance
// window.requestAnimationFrame(this.updateAnimation); // updateAnimation runs in the scope of the window
}
}
window.requestAnimationFrame = function requestAnimationFrame(callback) {
callback(new Date().getTime()); // calls the callback with one argument
}
我正在审查一些游戏代码,但我有一段不太明白。
var game = (function(){
// Start with our constructor
function Game(){
this.viewport = document.getElementById('viewport');
this.ctx = this.viewport.getContext('2d');
};
Game.prototype.updateAnimation = function(t){
// work out the delta time
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
// run relevent updates here
// queue the next animation time.
this.animationId = window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
}
// return game class
return Game;
})();
然后
// call new game object
var clientGame = new game();
// call event loop
clientGame.updateAnimation(new Date().getTime());
当请求 window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
运行时。它如何知道参数 t
的值。好像每次都会更新,但我不明白为什么。有人可以解释发生了什么事吗?谢谢。
编辑
Number
原型链上附加了一个名为 fixed()
的函数。这是为了清楚起见
Number.prototype.fixed = function(n) { n = n || 3; return parseFloat(this.toFixed(n)); };
首先代码可以写的更好,不需要每次都重新绑定函数,一次就够了(比如在对象初始化的时候)
其次,函数requestAnimationFrame
只接受一个参数,所以第二个参数没有意义,第一个参数是浏览器发送给回调的t
。
方法 .bind
不会更改函数参数(可能 arguments.callee
除外,尽管这是多余的)但仅更改函数的 context
因此第一个参数保持 t
(timestamp
)
更多信息https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
编辑
所以用户正在使用一些允许向 requestAnimationFrame 发送两个参数的 polyfill
所以requestAnimationFrame
有一个参数,一个回调函数,它获取时间戳作为参数。
绑定函数 returns 原始函数但在不同的范围内。因此 requestAnimationFrame
使用时间戳调用 updateAnimation,这是您的时间来源。
现在要了解 bind
调用背后的原因,您需要了解 JavaScript 中的范围。
当您定义一个函数并将其作为参数传递给另一个函数时,您实际上是在第二个函数的范围内调用第一个函数。这意味着如果你有一个 class 实例并且你想将一个实例方法作为回调传递给一个函数,你要么需要使用一个箭头函数来保留当前范围,要么你将方法绑定到正确的范围(你的 class实例)。
我希望下面的例子能更好地说明我在说什么。
class OuterScope {
constructor() {
this.label = 'test';
}
print() {
console.log(this.label);
}
}
function innerScope(callback) {
callback();
}
var scope = new OuterScope();
innerScope(scope.print); // throws error because the scope the function is called in doesn't have a property called label
innerScope(scope.print.bind(scope)); // prints label
现在将此应用于您的 requestAnimationFrame
问题:
class Game {
updateAnimation(t) {
// this.lastFrameTime would always be undefined when called without binding
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
window.requestAnimationFrame(this.updateAnimation.bind(this)); // updateAnimation now always runs in the scope of the current Game instance
// window.requestAnimationFrame(this.updateAnimation); // updateAnimation runs in the scope of the window
}
}
window.requestAnimationFrame = function requestAnimationFrame(callback) {
callback(new Date().getTime()); // calls the callback with one argument
}