12

Coffeescriptでクラスを作成する場合、インスタンスメソッドに太い矢印を使用しない理由はありますか?

編集:OK、それでは!素晴らしい返信です!:)
要約すると、問題は次のとおり です。-
より多くのメモリ を必要とします
-パッチを 適用できない
-質問をします、なぜそれがこのメソッドに使用されるのですか?
規則:
-関数をバインドするときは明示的にしてください。
-コンストラクターで太い矢印の付いたメソッドを宣言します。
-クラス宣言ではなく、好きなだけ使用してください。

4

2 に答える 2

18

はい、太い矢印を常に使用しない理由があります。実際、私は太った矢印の方法を決して使用しないことに賛成だと主張します:)

細い矢印と太い矢印の方法は、概念的に異なるものです。前者は、予想されるプロトタイプベースのJSコードにコンパイルされます。メソッドはクラスプロトタイプに属しています。一方、太い矢印のメソッドは、コンストラクターのコード内の各インスタンスに関連付けられています。

常に太い矢印のメソッドを使用することの最も明らかな欠点は、各クラスインスタンスがより多くのメモリを使用するようになり(独自のプロパティが多いため)、初期化が遅くなることです(これらのバインドされた関数を作成し、インスタンスごとに設定する必要があるため)創造された)。

fat-arrowメソッドを使用するもう1つの欠点は、メソッドが何であるかという通常の期待を破ることです。メソッドは、クラスのインスタンス間で共有される関数ではなくなりましたが、インスタンスごとに個別の関数になりました。これは、たとえば、クラスで定義された後でメソッドを変更する場合に問題を引き起こす可能性があります。

class Foo
  # Using fat-arrow method
  bar: (x) => alert x

# I have some Foos
foos = (new Foo for i in [1..3])

# And i want to path the bar method to add some logging. 
# This might be in another module or file entirely.
oldbar = Foo::bar
Foo::bar = (args...) ->
  console.log "Foo::bar called with", args
  oldbar.apply @, args

# The console.log will never be called here because the bar method 
# has already been bound to each instance and was not modified by 
# the above's patch.
foo.bar(i) for foo, i in foos

しかし、私の意見で最も重要な欠点は、より主観的なものです。ファットアローメソッドを導入すると、コード(および言語)が不必要に一貫性がなくなり、理解しにくくなります。

クラス定義でfat-arrowメソッドを導入する前に、「クラスのプロトタイプで値を使用して名前が<someProp>: <someVal>付けられたプロパティを宣言する」ことを意味することがわかっているため(特別な場合を除く)、コードの一貫性が失われます。が数値であるか関数であるかは関係ありませんが、プロトタイプのプロパティになります。fat-arrowedメソッドの導入により、もう1つの不要な特殊なケースが発生します。fat-arrowed関数の場合、他の値とはまったく異なる動作をします。<someProp><someVal><someProp> == 'constructor'<someVal><someVal>

また、もう1つの矛盾があります。太い矢印は、メソッド定義で使用された場合と他の場所で使用された場合でバインドがthis異なります。this外側(内部でclassthisクラスコンストラクターにバインドされている)を保持する代わりにthis、太い矢印のメソッドの内部は、メソッドが定義されたときに存在しないオブジェクト(つまり、クラスのインスタンス)です。

細い矢印のメソッドと太い矢印のメソッドを混在させると、コードを追跡するのも難しくなります。これは、開発者が太い矢印のメソッドを見るたびに、そのメソッドをインスタンスにバインドする必要がある理由を自問するためです。メソッドの宣言とそれが使用されている場所との間に直接的な相関関係はありません。そこでは、fat-arrowメソッドの必要性が生じます。


このすべてのために、私はファットアローメソッドを決して使用しないことをお勧めします。メソッドが宣言されている場所ではなく、メソッドが使用されるインスタンスにメソッドをバインドすることをお勧めします。例えば:

# Be explicit about 'onClick' being called on 'someObject':
$someJQueryElement.on 'click', (e) -> someObject.onClick e

# Instead of:
$someJQueryElement.on 'click', someObject.onClick

または、構築時にすべてのインスタンスでメソッドをバインドする必要がある場合は、そのことを明示してください。

# Instead of fat-arrow methods:
class A
  constructor: ->
    @bar = 42
  foo: => 
    console.log @bar

# Assing the method in the constructor, just like you would 
# do with any other own property
class A
  constructor: ->
    @bar = 42
    @foo = => 
      console.log @bar

2番目の定義では、最初の定義よりもメソッドでclass A何が起こっているかがはるかに明確であると思います。foo

最後に、太い矢印を使用することにまったく反対していないことに注意してください。これは非常に便利な構成であり、通常の機能に常に使用しています。メソッド定義内での使用は避けたいだけですclass:)


編集:ファットアローメソッドの使用に対する別のケース:デコレータ関数:

# A decorator function to profile another function.
profiled = (fn) ->
  (args...) ->
    console.profile()
    fn.apply @, args
    console.profileEnd()

class A
  bar: 10

  # This works as expected
  foo: profiled (baz) ->
    console.log "@bar + baz:", @bar + baz

  # This doesn't
  fatArrowedFoo: profiled (baz) =>
    console.log "@bar + baz:", @bar + baz

(new A).foo 5           # -> @bar + baz: 15
(new A).fatArrowedFoo 5 # -> @bar + baz: NaN
于 2012-12-03T16:12:55.287 に答える
12

別のビューを追加しましょう。

@epidemianが太った矢を避けるために表現した手の込んだ理由はよくありますが、次のことを考慮してください。

  • 一貫性のあるバグのないCoffeeScriptコードを記述できる限り、CoffeeScriptによって生成された「基本的なプロトタイプベースのJSコード」を(ほとんどまたはまったく)気にしない場合。
  • Javaで膨大な数の小さなクラスを作成する予定がない場合は、99%の時間を継承ツリーの上下で互いのメソッドを呼び出し、その過程でほとんど作業を行わないことになります。別の言い方をすれば、パフォーマンスに敏感な「内部ループ」がメソッド呼び出しを行うのに適した場所ではないことを認識している場合。
  • 実行時にクラスのメソッドを装飾、モンキーパッチ、またはその他の方法で変更する予定がない場合。
  • 将来の開発者がコードに取り組むために、ヘッダーコメントに太い矢印の使用法を記載する場合。

次に、メソッドと無名関数の両方で、習慣として常に太い矢印を使用することをお勧めします。

これにより、CoffeeScriptコードがよりシンプル、安全、直感的になります。これは、他のほとんどのプログラミング言語と同様に、実行時に関数やメソッドを呼び出す人に関係なく、メソッドを定義している現在のオブジェクトを常に参照するthisため@です。 。

より正式に言えば、太い矢印は、他の識別子と同様に、thisキーワード(およびその省略形)を完全に字句スコープにします。@プログラミング言語の歴史は、字句スコープが識別子をスコープするための最も直感的でエラーが発生しにくい方法であることを示しています。それがずっと前にすべての新しい言語の標準的な振る舞いになった理由です。

このパスを選択すると、細い矢印が例外になり、その場合に便利です。thisこれを使用して、独自のオブジェクトではなく、実行時に呼び出し元によって定義されたものを参照する必要がある特定のコールバックを準備します。これは直感に反する意味ですthisが、一部のJSライブラリでは、ユーザー提供の関数でこの種の動作が必要です。細い矢印は、これらのコードを強調表示するのに役立ちます。私の記憶が正しければ、jQueryは通常、関数の引数で必要なものをすべて提供するので、その人工的なものは無視できますがthis、他のライブラリはそれほど有益ではありません。

注意:CoffeeScript 1.6.1にはファットアローメソッドに関連するバグがあるため、それを回避する必要があります。以前のバージョンと新しいバージョンは問題ないはずです。

パフォーマンス

通常の(匿名)関数として使用する場合、太い矢印はオーバーヘッドを追加しません。メソッド宣言では、 RAMとCPUのオーバーヘッドがわずかに追加されます(実際には、メソッド呼び出しごとに数ナノ秒と数バイトのRAMが追加され、末尾呼び出しが最適化されたエンジンでは後者がなくなります)。

私見では、言語の明快さと安全性の太い矢印が引き換えに与えるのは、小さなオーバーヘッドを許容し、歓迎するのに十分な理由です。他の多くのCoffeeScriptイディオムは、言語の動作をより一貫性のあるものにし、エラーが発生しにくいようにする目的で、生成されたコード(forループなど)に独自の小さなオーバーヘッドを追加します。太い矢も例外ではありません。

于 2013-07-02T17:16:57.103 に答える