我有以下代码:
WaitModel = ->
timesDelayed = 0
maxDelay = 10
return this
WaitModel.prototype =
wait: ->
console.log 'waiting'
console.log this.timesDelayed, this.maxDelay
if this.timesDelayed >= this.maxDelay
console.log 'running'
this.timesDelayed = 0
else
this.timesDelayed++
setTimeout this.wait, 1000
return
new WaitModel().wait()
我认为这应该产生如下输出:
waiting
0 10
waiting
1 10
...
但它产生的输出如下:
waiting
0 10
waiting
undefined undefined
我在哪里取消this.timesDelayed
和this.maxDelay
?我误解了在这里制作物品的方法吗?
答案 0 :(得分:5)
jfriend00告诉你你做错了什么。在CoffeeScript中解决此问题的惯用方法是使用=>
(fat arrow)来定义wait
方法。我还de-JavaScripted你的CoffeeScript使其更具惯用性:
class WaitModel
constructor: (@timesDelayed = 0, @maxDelay = 10) ->
wait: =>
console.log 'waiting'
console.log @timesDelayed, @maxDelay
if @timesDelayed >= @maxDelay
console.log 'running'
@timesDelayed = 0
else
@timesDelayed++
setTimeout @wait, 1000
new WaitModel().wait()
答案 1 :(得分:2)
setTimeout
不会保留this
的值。您可以在调用this
之前将self
保存到名为setTimeout
的本地变量中,或者您想要调用它的任何内容并以此方式引用它。
我不知道coffeescript,但在javascript中,它会是这样的:
wait: function() {
var self = this;
if (this.timesDelayed >= this.maxDelay) {
console.log('running');
this.timesDelayed = 0;
} else {
this.timesDelayed++;
setTimeout(function() {self.wait()}, 1000);
}
}
答案 2 :(得分:2)
看起来CS有自动this
绑定。
setTimeout => @wait(),
1000
使用胖箭头,您可以将匿名函数中的this
视为其外部值。
答案 3 :(得分:1)
编辑:这比我更好地解释了:
http://bonsaiden.github.com/JavaScript-Garden/#function.this
您的示例在我的机器上提供此输出:
waiting
undefined undefined
waiting
undefined undefined
首先,构造函数不应返回任何内容,因此请删除return this
行。原因是因为new
创建了新对象,构造函数只是填充它。
在构造函数中,this
绑定到您正在创建的对象,而普通变量具有常规的局部范围。这意味着你必须在构造函数中说this.timeDelayed
等等 - 否则你的两个变量将在构造函数退出时超出范围,并且不会在以后显示为字段或其他任何内容。
通过这些更改,我的输出与您的输出匹配:
waiting
0 10
waiting
undefined undefined
现在谈谈你的问题。
setTimeout
将功能排队等待运行。函数只是函数 - 它们不会携带关于它们适用于哪个对象的额外信息,即使您将它们视为方法(如this.wait
)。这与this
非常相关,因为在Javascript中,this
关键字asways具有动态范围,这意味着调用者可以通过类似
someobject.foo()
或其他什么。在对foo
的调用中,this
绑定到someobject
。如果我们把它拿出来:
var foo = someobject.foo
foo()
在foo
内,this
将是未定义的。为了使其有效,我们不得不说:
foo.call(someobject)
这很重要,因为setTimeout
在超时函数运行时没有设置this
的值。相反,请替换您的电话:
setTimeout this.wait, 100
有类似的东西:
self = this
setTimeout (-> self.wait()), 100
这是有效的,因为该函数不再调用this
,而是调用self
这是一个普通变量。
Coffeescript包含一些技巧和快捷方式。首先,您可以使用胖箭头语法避免在闭包中捕获self
,该语法会自动将函数中的this
绑定到当前对象,无论它在何处被引用:
其次,您可以使用@作为this.
的快捷方式来编写实例变量/方法。因此,我的最终代码示例如下:
WaitModel = ->
@timesDelayed = 0
@maxDelay = 10
WaitModel.prototype =
wait: ->
console.log 'waiting'
console.log @timesDelayed, @maxDelay
if @timesDelayed >= @maxDelay
console.log 'running'
@timesDelayed = 0
else
@timesDelayed++
setTimeout (=> @wait()), 100
return
new WaitModel().wait()