Uncaught TypeError: Cannot read properties of undefined の原因と解決法

公開日
最終更新日
JavaScript エラー Uncaught TypeError: Cannot read properties of undefined

いつもは動くはずのJavaScriptが、あるページだけ動かない。デベロッパーツールを開くと「Uncaught TypeError: Cannot read properties of undefined」というエラーが出ている——JavaScriptを書いていると必ず一度は遭遇するエラーです。

結論から言うと、これは存在しない要素を参照し、そこからさらにプロパティを取得しようとしたときに起こります。解決策は、その要素が存在するときだけ処理を実行するよう、if文で囲むことです。この記事では、エラーの発生状況・原因・解決策を解説します。

エラー発生

いつも動くはずのJavaScriptが動かなかったので、Chromeのデベロッパーツールで確認したところ、次のエラーが出ていました。

「Uncaught TypeError: Cannot read properties of undefined」というエラーです。特定のページだけで発生し、そのせいでページ内の別のスクリプトまで止まっていました。

原因:存在しない要素のプロパティを取得しようとした

調べてみると、このエラーは未定義(undefined)の参照元からプロパティを取得しようとしたときに発生します。

今回のケースでは、全ページ共通で読み込むcommon.jsの中で、ページによっては存在しない.sidebarという要素を対象に処理を書いていました。そのため、.sidebarがないページでエラーが起き、さらにその下に書かれていたスクリプトまで動かなくなっていた、というわけです。

ポイントは、エラーが1か所で起きると、それ以降の処理がまとめて止まってしまうことです。「別の機能まで急に動かなくなった」ときは、手前でこの手のエラーが発生していないか、コンソールを疑ってみてください。

解決策:if文で存在チェックをする

まず、エラーが出ていた元のコードです。.sidebarの高さや位置を取得しています。

var target = $(".sidebar");
var targetHeight = target.outerHeight(true),
    targetTop = target.offset().top;

.sidebarが存在しないページでは、target.offset()undefinedを返し、そこから.topを取得しようとしてエラーになります。そこで、定義部分をif文で囲み、.sidebarが存在するときだけ処理を実行するようにします。

var target = $(".sidebar");
if ($(target).length) {
    var targetHeight = target.outerHeight(true),
        targetTop = target.offset().top;
}

jQueryでは、要素が見つからなくてもオブジェクト自体は返りますが、その中身は空です。.lengthで「マッチした要素が何個あるか」を確認できるので、これが0より大きいときだけ処理を実行すれば、要素がないページでのエラーを防げます。

もうひとつの手として、そもそもcommon.jsに書かず、.sidebarが存在するページにだけ個別でコードを書く方法もあります。共通ファイルに何でも詰め込むのではなく、ページ固有の処理は分けておくと、この種のエラーは根本的に起きにくくなります。

nullとundefinedの違い

よく似たエラーに「Cannot read properties of null」があります。どちらも「存在しないものからプロパティを取ろうとした」点は同じですが、参照元がnullundefinedかが異なります。

ざっくり言えば、getElementByIdなど「見つからなければnullを返す」処理ではnullのエラーに、値や戻り値がそもそも定義されていない場合はundefinedのエラーになりやすい、という傾向があります。いずれも対策は同じで、参照する前に存在チェックを挟むことに尽きます。

補足すると、if文で囲むほかに、オプショナルチェーン(?.)を使う方法もあります。target.offset()?.topのように書くと、参照元が存在しないときは結果がundefinedになるだけで、エラーで処理全体が止まるのを防げます。状況に応じてif文と使い分けると、コードを簡潔に保てます。

まとめ

  • 「Cannot read properties of undefined」は、存在しない要素のプロパティを取得したときのエラー
  • 全ページ共通のJSで、特定ページにしかない要素を対象にすると起こりやすい
  • if ($(target).length)で存在チェックし、要素があるときだけ処理する
  • ページ固有の処理は共通ファイルから分けておくと、根本的に防げる

1か所のエラーが後続の処理を巻き込んで止めてしまうのが、この手のエラーのやっかいなところです。要素を参照する前のひと手間で、スクリプト全体の安定性が大きく変わります。

IPPEI FUKUTA(株式会社バッズブルー 代表)

IPPEI FUKUTA(株式会社バッズブルー 代表)

WordPress専門のWeb制作者として15年・150サイト以上を担当。現場でつまずいた問題と解決策を、同じ制作者・フリーランスの方に向けて発信しています。無料のWeb便利ツール集「バドツール」を開発・運営中。