这两种实现之间有什么区别

What's the different between these two implementations

本文关键字:什么 区别 之间 两种 实现      更新时间:2023-09-26

片段 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

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

您在这里的问题是您使用的是简单对象而不是类,因此=>行为不符合您的预期。当你这样说时:

o =
  m: =>

这完全等同于说:

f = =>
o =
  m: f

这意味着m 内部的@(AKA this )是全局对象(window浏览器中或 AFAIK,node.js 中的空对象),而不是您期望的o

当你说:

class C
  m: =>

当您说o = new C时,CoffeeScript 会将m绑定到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

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

DemoFilter.onConfirmed => ...

被称为,@将再次b.这里我们还有另一个匿名绑定函数,由于@在此级别b,因此在调用console.log thisb this(AKA @

)。

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

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()

然后,您应该会看到您期望的行为。