我来自C#/ Java背景,它使用基于类的OO系统,但我还没有获得JavaScript / CoffeeScript原型OO系统。我在下面编写了一个CoffeeScript类,它允许我根据系统端首选项显示联系人的名称。我只能让joinNonEmpty(stringList, joinText)
方法属于原型并按照我在Java / C#land中调用静态方法的方式来调用它。
this.joinNonEmpty(...)
调用此方法?firstLastRender, lastFirstRender and firstOrNickThenLast
方法。但是在调用joinNonEmpty
帮助程序时,它不适用于那些方法?prefs = displayNameFormat: "FirstOrNickThenLast"
class DisplayNameRenderer
constructor: ->
@prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
# Why does this method have to be static (a class method)?
@joinNonEmpty: (stringList, joinText) ->
nonEmptyStrings = []
for s in stringList
nonEmptyStrings.push(s) if s isnt null and s isnt ""
nonEmptyStrings.join(joinText)
firstLastRender: (contact) ->
# TypeError: Object expected.
joinNonEmpty([contact.firstName, contact.lastName], ' ')
lastFirstRender: (contact) ->
# TypeError: Object doesn't support this method or property
this.joinNonEmpty([contact.lastName, contact.firstName], ', ')
firstOrNickThenLast: (contact) ->
# Works correctly.
DisplayNameRenderer.joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
@prefToRenderMap[prefs.displayNameFormat](contact)
contact = firstName: "Jonathan", nickname: "Jonny", lastName: "Appleseed"
dnr = new DisplayNameRenderer()
# => "Jonny Appleseed"
console.log dnr.render(contact)
感谢您抽出宝贵时间回答。
答案 0 :(得分:4)
this
(AKA @
)(如下所示)。所以当你这样做时:
@prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
您在@prefToRenderMap
实例变量中存储对三个函数的未绑定引用,而@prefToRenderMap
本身就是一个对象。然后,您尝试调用DisplayNameRenderer
实例中的方法,如下所示:
@prefToRenderMap[prefs.displayNameFormat](contact)
并且一切都崩溃了,因为这些方法是在错误的上下文中调用的,而@
并不是他们期望的那样。如果prefs
为'FirstOrNickThenLast'
,那么您有效地执行此操作:
@prefToRenderMap.FirstOrNickThenLast(contact)
和@
(AKA this
)将在@prefToRenderMap
方法中firstOrNickThenLast
。但是,当然,@prefToRenderMap
没有您尝试调用的任何方法,因此您会遇到各种错误。
一种解决方案是使用fat arrow (=>
)来定义方法:
胖箭
=>
既可以用来定义一个函数,也可以当场将它绑定到this
的当前值。
所以你可以这样做:
joinNonEmpty: (stringList, joinText) ->
#...
firstLastRender: (contact) =>
@joinNonEmpty([contact.firstName, contact.lastName], ' ')
一切都会成功。这是一个精简版演示,它还会向您显示this
问题:
您也可以通过名称引用方法来避免此问题。给定字符串中的方法名称m = 'some_method'
,您可以在JavaScript和CoffeeScript中调用此方法,如o[m]()
,结果与您说o.some_method()
时的结果相同。更好的结构看起来更像这样:
class DisplayNameRenderer
constructor: ->
@prefToRenderMap =
FirstOrNickThenLast: 'firstOrNickThenLast'
joinNonEmpty: (stringList, joinText) ->
#...
firstOrNickThenLast: (contact) ->
@joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
@[@prefToRenderMap['FirstOrNickThenLast']](contact)
请注意@prefToRenderMap
结构的更改及其在render
中的使用方式。并演示了这种方法:http://jsfiddle.net/ambiguous/DFYwu/
另外,您可以使用constructor
属性代替ClassName.class_method()
,而不是在实例方法中使用@constructor.class_method()
。另外,您通常会在CoffeeScript中说@method()
或@property
而不是this.method()
和this.property
。