📚

JavaScriptの関数の参照と無名関数について調べてみた

に公開3

はじめに

JavaScriptで関数を呼び出す際に、今までなんとなくfunc()funcを使っていたのでそれぞれの実行タイミングや役割についてしっかり理解するためにまとめてみました。

関数の実行タイミングについて

例えば以下のhandleClick関数があった場合、実行する際に複数の記法があると思います。

function handleClick() {
 console.log('クリックされました。');
}

パターンA

document.addEventListener('click', handleClick)

パターンB

document.addEventListener('click', handleClick())

パターンC

document.addEventListener('click', () => handleClick())

上記の3つのパターンの内、パターンBでは意図したタイミングで実行されません。
なぜか?
ここで関数の即時実行と参照についての理解が必要になります。

・即時実行とは(パターンB)
上記のhandleClick()で定義した場合は、関数を即時実行して返り値が返るだけになります。
その為、本来はクリックイベント時に関数を実行したいはずですが、DOMスクリプト評価時に実行されてしまうので、意図した挙動にはなりません。
(DOMについては以下の記事が参考になります。)
何度調べてもわからないDOMに決着をつける

・参照とは(パターンA)
関数の参照(関数そのもの)を渡しているだけ。実行タイミングはクリックイベント時。
イベントリスナーで登録している、クリック時のイベントとして適切なタイミングで実行されます。
イベントには関数そのもの(関数の参照)を渡します。

無名関数として実行する

ではパターンCの無名関数はどのタイミングで使用するのでしょうか。
基本的には以下の条件の場合に使用します。

  • 引数が設定されている。
// 引数が設定されている場合
document.addEventListener('click', () => handleClick('button1'));
  • 複数の関数をイベントリスナーで実行したい。
// 複数の処理を実行したい場合
document.addEventListener('click', () => {
    validateForm();
    handleClick();
    logEvent();
  });
  • ログや、バリデーションなどの処理をまとめたい。
// ログやバリデーションの処理をまとめる場合
document.addEventListener('click', () => {
  console.log('クリックされました')
})

利用シーンまとめ

  • イベント時だけ実行したい
    → 関数の参照を渡す(handleClick)。

  • 引数、複数処理、条件が必要な場合
    → 無名関数でラップする(例: () => handleClick('button1')() => { validateForm(); handleClick(); logEvent(); })。

参考サイト

JavaScript Primer
【JavaScript】無名関数とは/即時関数とは
JavaScriptの関数【関数宣言,アロー関数,無名関数,即時関数,コールバック関数,高階関数】

Discussion

junerjuner

javascript に 基本的に参照渡し(変数をそのまま関数に渡す仕組み)は無いのでは……?

というか インスタンスを渡すの意味で参照渡し を使っておられますでしょうか?

参照渡しに一番近い動作自体は import した変数が export 元での代入が反映されるのでそれっぽいすげ替え動作しますけれど。

shusaku009shusaku009

ご指摘いただきありがとうございます🙇🏻
インスタンスを渡すという意味での参照渡しではありませんでした。
関数の参照をしているということを書きたかったのですが、誤った表現のため修正いたしました。

junerjuner

いえ、javascript の関数は

function hoge() {
  return 1;
}

var hoge = new Function("return 1");

の様に解している為、インスタンス と言っています。宣言した時点で ニュアンス new していると同義です。
(関数宣言/関数式 でその new される文の挿入位置が違うだけです。