0

私はクラスベースのオブジェクト指向システムを使用するC#/ Javaのバックグラウンドを持っていますが、JavaScript/CoffeeScriptプロトタイプのオブジェクト指向システムをまだ取得していません。以下にCoffeeScriptクラスを作成しました。これにより、システム側の設定に従って連絡先の名前を表示できます。joinNonEmpty(stringList, joinText)メソッドをプロトタイプに属し、Java / C#ランドで静的メソッドを呼び出す方法で呼び出すことによってのみ、クラスを機能させることができます。

  1. を使用してこのメ​​ソッド呼び出しを行う方法はありthis.joinNonEmpty(...)ますか?
  2. firstLastRender, lastFirstRender and firstOrNickThenLastこれでコンストラクターのメソッドを参照できる理由を教えてください。joinNonEmptyしかし、ヘルパーを呼び出すときにそれらのメソッドからは機能しませんか?
  3. これは、設定マップを介して適切なメソッドを見つける方法と関係がありますか?
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)

お時間を割いていただきありがとうございます。

4

1 に答える 1

4

this(AKA @)は、関数が呼び出されたときに決定されます(以下の例外を除く)。したがって、これを行うと:

@prefToRenderMap =
    FirstLast: this.firstLastRender
    LastFirst: this.lastFirstRender
    FirstOrNickThenLast: this.firstOrNickThenLast

3つの関数へのバインドされていない参照を@prefToRenderMapインスタンス変数に格納しており、@prefToRenderMapそれ自体がオブジェクトです。DisplayNameRenderer次に、次のようにインスタンスのメソッドを呼び出そうとします。

@prefToRenderMap[prefs.displayNameFormat](contact)

@そして、メソッドが間違ったコンテキストで呼び出され、期待したものではないため、すべてがバラバラになります。もしそうなら、あなたはこれを効果的に行っていますprefs'FirstOrNickThenLast'

@prefToRenderMap.FirstOrNickThenLast(contact)

および@(AKA this)はメソッド@prefToRenderMap内にあります。firstOrNickThenLastただし、もちろん、@prefToRenderMap呼び出そうとしているメソッドがないため、さまざまなエラーが発生します。

1つの解決策は、太い矢印(=>を使用してメソッドを定義することです。

太い矢印=>は、関数を定義することと、その場で現在の値にバインドすることの両方に使用できますthis

したがって、次のようなものがあります。

joinNonEmpty: (stringList, joinText) ->
    #...

firstLastRender: (contact) =>
    @joinNonEmpty([contact.firstName, contact.lastName], ' ')

そしてすべてがうまくいくでしょう。thisこれは、問題を示す簡略化されたデモです。

http://jsfiddle.net/ambiguous/RAPJw/1/

メソッドを名前で参照することで、この問題を回避することもできます。文字列にメソッド名を指定すると、JavaScriptとCoffeeScriptの両方でm = 'some_method'このようにそのメソッドを呼び出すことができ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/


余談ClassName.class_method()ですが、インスタンスメソッド内で言う代わりに、代わりにconstructorプロパティを使用できます@constructor.class_method()。また、あなたは通常、CoffeeScriptではなくまたはと言い@method()ます。@propertythis.method()this.property

于 2012-04-23T18:56:54.637 に答える