这两个实现有什么不同
What's the different between these two implementations
代码段 A:
DemoFilter =
onConfirmed: (cb) ->
cb()
a =
onConfirmed: (callback) ->
this.callback = callback
confirm: ->
this.callback()
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log this # output: {} or Object window on browser
b.init()
a.confirm()
代码段 B:
DemoFilter =
onConfirmed: (cb) ->
cb()
a =
onConfirmed: (callback) ->
this.callback = callback
confirm: ->
this.callback()
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed =>
console.log this # output: Object b
# mycallback: =>
# console.log this
b.init()
a.confirm()
为什么这些console.log
输出不一样?
在节点环境中:
A:输出{}
B:输出Object b
我发现编译结果完全一样,我想不通为什么结果不一样。
您的问题是您使用的是简单对象而不是 classes,因此 =>
的行为方式与您期望的不同。当你这样说时:
o =
m: =>
这和说的完全一样:
f = =>
o =
m: f
这意味着 m
中的 @
(AKA this
) 是全局对象(浏览器中的 window
或者,AFAIK,node.js) 而不是您期望的 o
。
当你说:
class C
m: =>
当您说 o = new C
时,CoffeeScript 会将 m
绑定到 C
实例 。如果您使用普通对象文字而不是 class,则没有特殊的构造阶段来设置绑定,也没有 =>
的 class 实例将函数绑定到。
如果我们回到你的第一个案例:
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log this
mycallback
将绑定到任何全局对象。此外,@
(又名 this
)的值取决于函数的调用方式而不是函数的定义位置(当然不包括绑定函数),所以如果你说:
b.init()
然后 init
内的 @
将是 b
。然后你交给的匿名函数a.onConfirmed
:
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
将绑定到 b
,因为当您定义该函数时 @
是 b
。但是 mycallback
不会在意,因为它已经绑定到全局对象。
第二种情况:
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed =>
console.log this
当调用 init
时,我们再次将 @
变为 b
,并且传递给 a.onConfirmed
的匿名函数将再次绑定到 b
。这意味着当:
DemoFilter.onConfirmed => ...
被调用,@
将再次成为 b
。这里我们有另一个匿名绑定函数,因为 @
是 b
在这个级别我们有 this
(又名 @
)当 console.log this
时是 b
被调用。
如果您使用 classes 而不仅仅是对象:
class A
onConfirmed: (@callback) ->
confirm: ->
@callback()
class B
constructor: (a) ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log @
a = new A
b = new B(a)
a.confirm()
那么您应该会看到预期的行为。
代码段 A:
DemoFilter =
onConfirmed: (cb) ->
cb()
a =
onConfirmed: (callback) ->
this.callback = callback
confirm: ->
this.callback()
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log this # output: {} or Object window on browser
b.init()
a.confirm()
代码段 B:
DemoFilter =
onConfirmed: (cb) ->
cb()
a =
onConfirmed: (callback) ->
this.callback = callback
confirm: ->
this.callback()
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed =>
console.log this # output: Object b
# mycallback: =>
# console.log this
b.init()
a.confirm()
为什么这些console.log
输出不一样?
在节点环境中:
A:输出{}
B:输出Object b
我发现编译结果完全一样,我想不通为什么结果不一样。
您的问题是您使用的是简单对象而不是 classes,因此 =>
的行为方式与您期望的不同。当你这样说时:
o =
m: =>
这和说的完全一样:
f = =>
o =
m: f
这意味着 m
中的 @
(AKA this
) 是全局对象(浏览器中的 window
或者,AFAIK,node.js) 而不是您期望的 o
。
当你说:
class C
m: =>
当您说 o = new C
时,CoffeeScript 会将 m
绑定到 C
实例 。如果您使用普通对象文字而不是 class,则没有特殊的构造阶段来设置绑定,也没有 =>
的 class 实例将函数绑定到。
如果我们回到你的第一个案例:
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log this
mycallback
将绑定到任何全局对象。此外,@
(又名 this
)的值取决于函数的调用方式而不是函数的定义位置(当然不包括绑定函数),所以如果你说:
b.init()
然后 init
内的 @
将是 b
。然后你交给的匿名函数a.onConfirmed
:
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
将绑定到 b
,因为当您定义该函数时 @
是 b
。但是 mycallback
不会在意,因为它已经绑定到全局对象。
第二种情况:
b =
init: ->
a.onConfirmed =>
DemoFilter.onConfirmed =>
console.log this
当调用 init
时,我们再次将 @
变为 b
,并且传递给 a.onConfirmed
的匿名函数将再次绑定到 b
。这意味着当:
DemoFilter.onConfirmed => ...
被调用,@
将再次成为 b
。这里我们有另一个匿名绑定函数,因为 @
是 b
在这个级别我们有 this
(又名 @
)当 console.log this
时是 b
被调用。
如果您使用 classes 而不仅仅是对象:
class A
onConfirmed: (@callback) ->
confirm: ->
@callback()
class B
constructor: (a) ->
a.onConfirmed =>
DemoFilter.onConfirmed @mycallback
mycallback: =>
console.log @
a = new A
b = new B(a)
a.confirm()
那么您应该会看到预期的行为。