在coffeescript中同时提供object.property和object.property.method()

时间:2013-02-08 01:15:34

标签: coffeescript

[更新] 我的问题可能不够明确...... 进一步澄清我想要完成的事情:

我检索这样的对象:

p =
  name:
    first: 'alan'
    last: 'smith'

并且想要创建一个结构(一个类,多个类?),以便能够最终编写这样的东西:

person.name # alan smith
person.name.toCap() #Alan Smith
person.name.first # alan
person.name.first.toCap() # Alan
person.name.last # smith
person.name.last.toCap() # Smith
...

所以:

  1. 有没有办法同时拥有person.name和person.name.first?
  2. 是否有更好的方法使用方法扩展对象属性,而不是扩展本机类型,如 String

  3. [原始]

    在咖啡中寻找正确的方法:

    console.log person.name.last #smith
    console.log person.name.last.capitalize() # SMITH
    console.log person.name.last.initial() # S
    

    我已经提出了以下解决方案,但我想确保这是可行的方法......

    String::toCap = (remainingToLower=false) -> 
      @[0].toUpperCase() + if remainingToLower then @[1..-1].toLowerCase() 
                                               else @[1..-1]
    Number::random = (percent) ->
      offset = @ * percent / 100
      parseInt(Math.floor(Math.random() * 2 * offset) + @ - offset)
    
    class Name
      constructor: (@first, @last) ->
    
    class Person
      constructor: (@name, @age) ->
      toString: () => "#{@name.first.toCap(true)} #{@name.last.toCap(true)} 
                      (#{@age.random(25)})"
    
    # GO --------------------------->
    
    p = new Person(new Name, 18)
    p.name.first = 'alaN'
    p.name.last = 'smith'
    
    console.log "#{p.toString()}"
    

    感谢您的反馈。

    Plunk Here

1 个答案:

答案 0 :(得分:0)

<强>上下文
我有这个原始数据:

data =
  name:
    first: 'alan'
    last: 'smith'  
  age: 18  
  address: [  
    {  
      name: 'work'  
      street: '1600 amphitheatre parkway'  
      city: 'mountain view'  
      zip: 'CA 94043'  
    },{  
      name: 'home'  
      street: '1 infinite loop'  
      city: 'cupertino'  
      zip: 'CA 95014'  
    }]  

想要创建一个结构来操纵我的数据:

p = New Person(data)
console.log """
  #{p}                        # alan smith (18), 2 address lines
  #{p.name},                  # alan smith
  #{p.name.first},            # alan
  #{p.address}                # 2 address lines
  #{p.address.work}           # 1600 amphitheatre parkway, mountain view, CA 94043
  #{p.address.work.street}    # 1600 amphitheatre parkway
"""

此外,我希望能够将自定义方法应用于任何成员。 例如,假设toCap()是一个大写字符串每个单词的方法:

console.log """
  #{p.name.toCap()},                # Alan Smith
  #{p.name.first.toCap()}           # Alan
  #{p.address.work.toCap()}         # 1600 Amphitheatre Parkway, Moutain View, CA 94043
  #{p.address.work.street.toCap()}  # 1600 Amphitheatre Parkway  
"""

解决方案(有关完整代码,请参阅此Plunk

  • 使用嵌套类

    class Person
      constructor: (data) ->
        @name = new Name(data.name)
        @address = new AddressList(data.address)
    
  • 动态创建成员

    class AddressList
      constructor: (list) ->    
        @[addr.name] = new Address(addr) for addr in list    
    
  • 包装您的属性或使用基类而不是扩展本机对象

    class StringProperty
      constructor: (@_value) ->
      toString: => 
        @_value
      toCap: (remainingToLower=false) =>
        _words = @_value.split ' '
        (@_toCap(w,remainingToLower) for w in _words).join ' '     
      _toCap : (s, r) ->
        s[0].toUpperCase() + if r then s[1..-1].toLowerCase() else s[1..-1]
    

    ...并直接使用它们......

    class Name
      constructor: (name) ->
        @first = new StringProperty(name.first)
        @last = new StringProperty(name.last)
      toString: =>
        "#{@first} #{@last}"
      toCap: =>
        "#{@first.toCap()} #{@last.toCap()}"
    

    ...或动态创建成员:

    @[k] = new StringProperty(data[k]) for k of data when k in Address.fields
    
  • 不要忘记按上面覆盖toString()