JavaScriptって括弧のお化け

はじめに

コロナウイルスに戦々恐々の廣田です。
皆様も体にはお気をつけて…

憂鬱な今日この頃ですが、最近の業務中の癒しはslackが未読を始末した時に励ましてくれることです。
癒されすぎてキャプチャを集めちゃいました。

さて、今回はJavaScriptが括弧の有無で挙動が全然違うので調べてみました。

コールバック関数の書き方

Vue.jsで画面上の検索ボタンを押したらモーダル画面が開いて一覧から検索を行えるような機能を作っていた時のこと。 つぎのようなコードで上手く動かなかったのですが、どこが問題でしょうか🤔
<!--HTML側--> 
<div id="js-mainArea">
<button type="button" @click="search">検索</button> 
</div>
//本体のVueインスタンス
new Vue({
   el: '#js-mainArea',
   data: {},
   methods: {
       search() {
           EventBus.$emit('open-search-modal');
       },
   },
});
//モーダルのVueインスタンス
new Vue({
   el: '#js-search-modal',
   data: {
       isOpen = false
   },
   created: function () {
       EventBus.$on('open-search-modal', this.open())
   },
   methods: {
       open() {
           console.log('open');
           this.isOpen = true;
       },
  },
});
すごく初歩的なところだと思うのですが、検索ボタンを押したときemitしたイベントを捕捉している以下の箇所が原因でした。
EventBus.$on('open-search-modal', this.open()) 
イベントハンドラとしてコールバック関数を指定したいので正しくはこうですよね。
EventBus.$on('open-search-modal', this.open)
はい。括弧を書いていたのが間違いでした。

うっかり括弧付きで書いてしまうことがあるのですが、どうして括弧付きで書くとダメなんでしょう。

「括弧をつけるとメソッドが即座に実行されてしまう」
「コールバック関数を書く時は括弧無しで書く」

コールバック関数として渡したいときは括弧書いちゃいけないんですね
わかりました~

…でもなんで?
納得できなかったので調べてみました🧐

具体的な例で考えてみる

わかりやすいようにSquare関数を用意します。
function Square(number) {
  return number*number;
}
これは以下と同等です。
const Square = function(number) {
  return number*number;
}
2つめのように表現すると関数も他の定数や数値のように受け渡しが可能なものだということがわかりやすくなりました。(こういうのを第一級オブジェクトというらしいです。)

括弧ありでの挙動

let number = 3;
let result = Square(number);
このときSquare関数が引数にnumberをとって実行され、変数resultには「9」がセットされます。

括弧なしでの挙動

let number = 3;
let result = Square;
このとき変数resultにはSquare関数そのものがセットされます。
つまりresult()とすることでSquare関数を実行できるということです。
let output = result(3); 
console.log(output); // equal to 9
これは以下と同等です。
let output = Square(3);
resultを呼びだすとき、実際にはSquare関数を参照しているんですね。


 

今回の事例に戻って

さて最初のVueの例に戻ります。
created: function () {
       EventBus.$on('open-search-modal', this.open())
   },
   methods: {
       open() {
           console.log('open');
           this.isOpen = true;
       },
  },
},
上記のように書いた時、createdの段階でopen関数が実行されてコンソールに”open”が表示されます。
open関数は変数isOpenをtrueにするのみの関数のなのでその実行結果がイベントハンドラとして渡されても、イベント捕捉時に何も実行されません。

open() { 
    console.log('open'); 
    this.isOpen = true; 
},
//これは以下と同じ
open = function() {
    console.log('open'); 
    this.isOpen = true;
}
 
なのでイベントハンドラにopen関数自体をコールバック関数として渡すためには括弧無しのthis.openと書かなければいけません。
納得できましたε-(‘∀`;)ホッ


とってとっても参考になりました。
https://stackoverflow.com/questions/3246928/in-javascript-does-it-make-a-difference-if-i-call-a-function-with-parentheses

アロー関数とかほんと括弧のお化け。arimasさんに同意します。
https://qiita.com/arimas/items/448f411e78d12f7d5208