なぜ “return false” が動作しないのか?イベント伝播とデフォルトアクションの核心を突く
フロントエンド開発の現場において、初心者が最初に直面する「不可解な挙動」の一つが、`return false` を記述したにもかかわらず、期待した制御が行われないという現象です。jQuery時代には「とりあえず書いておけば動く」という魔法の呪文のように扱われていた `return false` ですが、現代の標準的なJavaScript(Vanilla JS)において、なぜこれが意図通りに動作しないケースがあるのか、その技術的背景を深く掘り下げます。
return false が隠蔽している3つの挙動
まず、`return false` という記述が実際には何を行っているのかを理解する必要があります。現代のモダンブラウザにおいて、イベントハンドラ内で `return false` を返すことは、実質的に以下の3つの動作を同時に実行することと同義です。
1. event.preventDefault():要素が持つデフォルトのアクションをキャンセルする。
2. event.stopPropagation():イベントのバブリング(親要素への伝播)を停止する。
3. 関数の実行終了:その後のコードの実行を停止する。
しかし、この挙動が保証されるのは「jQueryのイベントシステムを経由した場合」に限られます。ネイティブの `addEventListener` を使用する場合、`return false` を書いてもブラウザは単に「falseという値を返した」としか認識しません。この値がイベントシステムに伝わることはなく、デフォルトのアクション(リンクの遷移やフォームの送信)はそのまま実行されてしまいます。これが、現代のフロントエンド開発で `return false` が「動作しない」と感じる最大の理由です。
イベント伝播とpreventDefaultのメカニズム
Webブラウザにおけるイベントは、キャプチャリングフェーズ、ターゲットフェーズ、バブリングフェーズという3つの段階を経て伝播します。
デフォルトのアクション(例:aタグのページ遷移、submitボタンによるフォーム送信)は、ブラウザがイベントを処理した後に自動的にトリガーされます。この動作を抑制するためには、明示的に `event.preventDefault()` を呼び出す必要があります。
ここで重要なのは、`event.preventDefault()` は「イベントの伝播」を止めるわけではないという点です。一方で `event.stopPropagation()` はイベントの伝播を止めますが、「デフォルトのアクション」は止めません。`return false` はこの両方をやってのけるため、開発者にとって都合の良いショートカットとして重宝されてきましたが、ネイティブAPIではこの「両方を同時に行う」という抽象化は提供されていないのです。
サンプルコード:正しい制御の実装
ネイティブなJavaScriptで、リンクの遷移を阻止しつつ、後続の処理を制御するための正しい実装例を以下に示します。
// 不適切な実装例(動作しない)
const link = document.querySelector('a');
link.addEventListener('click', function(event) {
// これだけでは遷移は止まりません
return false;
});
// 適切な実装例
const link = document.querySelector('a');
link.addEventListener('click', function(event) {
// 1. デフォルトのアクションをキャンセル
event.preventDefault();
// 2. 必要であればバブリングも停止
event.stopPropagation();
// 3. 独自のビジネスロジックを実行
console.log('リンクの遷移を阻止しました');
});
このように、明示的にメソッドを呼び出すことが、現代のフロントエンド開発におけるベストプラクティスです。これにより、コードの意図が明確になり、デバッグも容易になります。
なぜjQueryでは動いていたのか
jQueryが全盛期だった時代、jQueryのイベントハンドラは、関数内で `return false` を検知すると、内部的に `event.preventDefault()` と `event.stopPropagation()` を自動的に呼び出すというラッパー機能を備えていました。
しかし、現代のフロントエンド開発では、React、Vue、Angularといったフレームワークが主流です。これらのフレームワークも独自のイベントシステムを持っていますが、基本的にはネイティブのイベントオブジェクトをラップしているに過ぎません。Reactの `SyntheticEvent` を使用している場合でも、`return false` は何の効力も持ちません。フレームワークの仕様とネイティブの仕様を混同することが、バグの温床となります。
実務アドバイス:保守性を高める設計
実務において「return falseを多用する」という習慣は、コードの可読性を下げるリスクがあります。以下の点に注意して設計を行ってください。
1. 明示的なメソッド呼び出し:`event.preventDefault()` を使用すること。これにより、他の開発者がコードを読んだときに「何を止めようとしているのか」が即座に理解できます。
2. 責任の分離:イベントハンドラ内で複雑なビジネスロジックを書くのではなく、分離した関数に切り出しましょう。`preventDefault` はイベントハンドラの冒頭に記述し、関数の責務を明確にします。
3. 非同期処理への注意:`async/await` を使用する場合、`event.preventDefault()` は非同期処理の前に行う必要があります。さもないと、非同期処理の完了を待っている間にデフォルトのアクションが実行されてしまう可能性があります。
4. バブリングの制御は慎重に:`stopPropagation()` を多用すると、親要素でイベントをキャッチして一括管理する「イベント委譲(Event Delegation)」のパターンが機能しなくなります。本当に伝播を止める必要があるのか、設計を再考すべきです。
まとめ
`return false` が動作しないと感じるのは、あなたが古い慣習と現代の仕様の境界線にいるからです。ブラウザのネイティブAPIが `return false` をイベント制御のトリガーとして扱わない以上、私たちはそれに適応しなければなりません。
`event.preventDefault()` でデフォルト動作を止め、`event.stopPropagation()` で伝播を止める。この二つのメソッドを使い分けることは、フロントエンドエンジニアとしての基礎体力です。ショートカットに頼らず、ブラウザのイベントモデルを深く理解することで、より堅牢で予測可能なコードを書くことが可能になります。
「なぜ動かないのか」という疑問は、技術力を向上させる絶好の機会です。今回解説したメカニズムを理解し、今後の開発において「なぜそのコードを書くのか」を常に言語化できるようにしておきましょう。それが、シニアエンジニアへとステップアップするための重要な一歩となります。

コメント