这两种实现之间的区别是什么

时间:2016-02-29 14:28:16

标签: javascript coffeescript this

代码段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输出不一样?

在节点环境中:

答:输出{}
B:输出Object b

我发现编译结果完全相同,我无法弄清楚为什么结果不同。

1 个答案:

答案 0 :(得分:2)

您的问题是,您使用简单的对象而不是类,因此=>的行为方式与您预期的不同。当你这样说:

o =
  m: =>

与说:

完全一样
f = =>
o =
  m: f

这意味着@中的this(AKA m)是浏览器中的全局对象(window,或者是Node.js中的空对象AFAIK而不是像你期望的那样o

当你说:

class C
  m: =>

当您说m时,CoffeeScript会将C绑定到o = new C 实例。如果使用普通对象文字而不是类,则没有特殊的构造阶段来设置绑定,也没有=>类的实例将函数绑定到。

如果我们回到你的第一个案例:

b =
  init: ->
    a.onConfirmed =>
       DemoFilter.onConfirmed @mycallback
  mycallback: =>
    console.log this

mycallback将绑定到全局对象。此外,@(AKA this)的值取决于函数的调用方式而不是函数的定义(当然,限制函数),所以如果你说:

b.init()

然后@内的init将为b。然后是你提交给a.onConfirmed的匿名函数:

a.onConfirmed =>
   DemoFilter.onConfirmed @mycallback

将绑定到b,因为@在定义该函数时为b。但是mycallback不关心,因为它已经绑定到全局对象。

在你的第二个案例中:

b =
  init: ->
    a.onConfirmed =>
       DemoFilter.onConfirmed =>
         console.log this

我们在调用@时再次binit,并且传递给a.onConfirmed的匿名函数将再次绑定到b。这意味着:

DemoFilter.onConfirmed => ...

被调用,@将再次成为b。这里我们有另一个匿名绑定函数,由于此@ bthis,因此@ b {AKA console.log thisclass 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() 被称为。

如果您使用的是类而不仅仅是对象:

<style name="ThemeOverlay.MyApp.ActionBar" parent="ThemeOverlay.AppCompat.ActionBar">
        <item name="android:textColorPrimary">@color/white</item>
        <item name="android:textColorSecondary">@color/white</item>
    </style>

那么你应该看到你期待的行为。