我有一个我在画布上使用的函数,我正在尝试清除使用.animate
函数调用的间隔,但是当我调用.unbind();
时,它仍会记录未定义的,当它应该记录超时,我不确定为什么它不起作用,也许你们可以帮忙
function Character(model, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
this.model = model;
this.srcX = srcX;
this.srcY = srcY;
this.srcW = srcW;
this.srcH = srcH;
this.destX = destX;
this.destY = destY;
this.destW = destW;
this.destH = destH;
this.timeout = undefined;
}
Character.prototype = {
draw: function() {
return ctx.drawImage(this.model, this.srcX, this.srcY, this.srcW, this.srcH,
this.destX, this.destY, this.destW, this.destH);
},
animate: function(claymation) {
var top = this; <<<<<--------Set the this variable
var queue = (function() {
var that = this;
var active = false;
if (!this.active) {
(function runQueue(i) {
that.active = true;
var length = claymation.length -1;
>>>>-Set the timeout top.timeout = setTimeout(function() {
claymation[i].action();
if ( i < length ) {
runQueue(i + 1);
if (i === length - 1) {
that.active = false;
}
}
}, claymation[i].time);
})(0);
}
})();
return queue;
},
update: function(callback) {
callback();
},
unbind: function() {
console.log(this.timeout); < Logs undefined
clearTimeout(this.timeout);
console.log(this.timeout); < Also logs undefined?
}
}
更新
我打电话给unbind:
player = new Character(playerModel, 0, 130, 100, 100, 150, 150, 100, 100)
if (e.which === 39) {
player.unbind();
key = undefined;
}
完整源代码:https://github.com/Gacnt/FirstGame/blob/master/public/javascripts/superGame.js#L50-L77
答案 0 :(得分:3)
您的animate
功能搞砸了。你已经看到有必要将this
reference存储在一个额外的变量(that
,top
,无论如何),因为它从调用到调用以及从函数到函数的变化,但是你失败了做得正确。
var top = this;
var queue = (function() {
var that = this;
var active = false;
if (!this.active) {
// use
that.active = true;
// or
top.timeout = …;
// or
that.active = false;
}
})();
虽然top
是正确的并且会引用您调用该方法的Character
实例,但that
绝对不是 - 它将引用全局上下文(window
) ,这是正常(立即)调用函数(表达式)s中的默认this
值。因此,this.active
几乎没有值,并且您的timeout
属性未设置。另请注意,IIFE没有return
任何内容,因此queue
将为undefined
。
相反,您似乎想要使用该本地active
变量。那就做吧!您不必使用某些Java - this
- like关键字来引用“local” - 该变量只是范围链中的下一个,因此将使用它。
我不完全确定,但看起来你想要
Character.prototype.animate = function(claymation) {
var that = this; // variable pointing to context
var active = false; // again, simple local variable declaration
if (!active) {
(function runQueue(i) {
active = true; // use the variable
var length = claymation.length -1;
that.timeout = setTimeout(function() { // use property of "outer" context
claymation[i].action();
if ( i < length ) {
runQueue(i + 1);
if (i + 1 === length) {
active = false; // variable, again!
}
}
}, claymation[i].time);
})(0);
}
};
答案 1 :(得分:0)
Bergi所说的是:
animate: function(claymation) {
var top = this;
在这里你设置top来引用它,这是实例(我宁愿称之为字符,所以你知道它是Character的一个实例)。然后你有一个IIFE,它有自己的执行上下文和 this 的新值:
var queue = (function() {
var that = this;
这里 设置了IIFE的 this ,未设置为默认为全局/窗口对象,或者如果处于严格模式,将保留未定义。
var active = false;
if (!this.active) {
所以在这里你得到 window.active ,这可能是第一次未定义,所以测试是真的。稍后你会这样做:
(function runQueue(i) {
that.active = true;
将window.active
设为true。另外,你正在做:
(function runQueue(i) {
...
})(0);
如果你只是传递一个固定值,就没有任何需要IIFE,只需在0
处使用i
并移除IIFE,只需使用函数体,你就不应该在范围链上需要额外的对象。
最后,两个IIFE都没有返回任何内容,因此 queue 仍未定义,因此:
})();
return queue;
返回udefined
值。