【Vue】一体いつから括弧無しメソッドと括弧有りメソッドが同じだと錯覚していた？

# Vueでメソッドの末尾に`()`をつけた時とつけない時の挙動の違い

以前からVueを使っていて疑問だったことがありました。

それはVueの`methods`で定義したメソッド（関数）をテンプレートで使うとき、
**末尾に`()`をつけたメソッドと`()`のないメソッドの両方を使用可能**であるという事実です。

具体的にどういうことかコードで説明してみます。

下のコードで`method`という名のメソッドがVueの`methods`プロパティで定義されているとします。

このときtemplate内から呼び出すときは、`method()`と`method`の両方が使えてしまいます。
（ちなみに`<script></script>`タグ内では括弧無しの呼び出し`method`は呼び出しになりません）

```vue
<template>
  <!-- どちらの書き方でも正常に実行される -->
  <div>
    <div id="example1">
      <!-- メソッド名（括弧無し）をv-onに渡した場合 -->
      <button @click="method">括弧無し</button>
    </div>

    <div id="example2">
      <!-- メソッド名（括弧有り）をv-onに渡した場合 -->
      <button @click="method()">括弧有り</button>
    </div>
  </div>
</template>
```

はじめは、括弧なし呼び出しは括弧あり呼び出しの省略形ぐらいに考えていたのですが、調べてみたところ大きな違いがありました。

Vue詳しい方にとっては当たり前なのかもしれませんが、備忘録として残しておくことに。

## 調べてわかったこと
結論から書くと、次のような違いがあるということでした。

### 括弧あり呼び出し
- 引数無しの場合は引数は何も取らずに（当然ですが）、メソッドが呼び出されるだけ
- 引数がある場合も定義にしたがってメソッドが呼び出される

特に問題なく、普通のJSの関数（メソッド）と同じ挙動だと思います。

### 括弧なし呼び出し
- 引数として**`Event`オブジェクトが暗黙に渡され、**メソッドが実行される

一見、引数が何も無いので、単に引数無しのメソッドが呼び出されているように見えますが、実はそのDOMで発生したEventオブジェクトが引数にわたっています。

## 例を交えて

以下参考にしたページです。

> 
- [Parentheses while calling a method in Vue](https://stackoverflow.com/questions/50635404/parentheses-while-calling-a-method-in-vue/50635834)
- [Method Event Handlers](https://vuejs.org/v2/guide/events.html#Method-Event-Handlers)
- [Difference when calling a method function with or without brackets](https://forum.vuejs.org/t/difference-when-calling-a-method-function-with-or-without-brackets/41764/)

次の例では比較のためにブラウザのアラートを出す3種のボタンを用意してます。

VueのJS側では、対応するVueインスタンスの`methods`プロパティに`say()`というメソッドを用意しています。`say()`メソッドは**引数を１つ受け取る**ように定義されています。また、内部では受け取ったEventオブジェクトのタイプをJSの`alert()`で表示する処理が書かれています。

<p class="codepen" data-height="860" data-theme-id="light" data-default-tab="js,result" data-user="masa_u1128" data-slug-hash="PoZLwYb" style="height: 860px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="PoZLwYb">
  <span>See the Pen <a href="https://codepen.io/masa_u1128/pen/PoZLwYb">
  PoZLwYb</a> by Masa U. (<a href="https://codepen.io/masa_u1128">@masa_u1128</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

まず、「括弧有り」ボタンをクリックすると、「`TypeError: Cannot read property 'type' of undefined`」とアラート表示されます。引数を渡していないのでエラーが出るのは当然でしょう。

次に、「括弧無し」ボタンをクリックすると、「Eventオブジェクトのタイプはclickです」とアラート表示されます。


**<font color="Tomato">何...だと...？</font>**

**繰り返しになりますが、引数は渡していません**。これは**引数に暗黙的に`Event`オブジェクトが渡されている**ためです。

最後に「括弧有り（引数に`$event`を渡している）」ボタンを押してみましょう。この場合は引数に`$event`という変数を渡してメソッド呼び出しをしています。結果は「括弧無し」ボタンと同じになります。ちなみに頭に`$`のついた変数はVueであらかじめ用意された特殊な変数で、`$event`はDOMイベントオブジェクトを格納する変数として使われます。

おそらく、括弧無し呼び出しのときは`$event`が暗黙的に引数として渡されているということだと思います。

## まとめ
以上のことから、括弧無し呼び出しでは暗黙的に引数に`Event`オブジェクトが渡されてることが分かりました。

普通に使っている分には括弧有りと無しのどちらを使っても問題ないような気がしますが、括弧無しの場合は１つ注意したいケースがあります。

それはデフォルト引数を使っている場合です。**デフォルト引数があると、暗黙的に渡されるEventオブジェクトが引数となってしまうので、期待する結果と異なる結果が得られてしまいます**。この場合は括弧有りの呼び出しを使うべきでしょう。

個人的には括弧をつけた方がぱっと見でメソッドであることが分かりやすく、算出プロパティと区別しやすいのでEventオブジェクトを使わない場合は括弧有り呼び出しを使った方がいいのかなと思っています。

（それにしても、公式ドキュメントを読んでもさらっと数行で済ましているので違いを理解するのに時間が少しかかった:sweat_smile:）