JS memo

お洒落にJavaScript。

2019年2月2日20:00

javascriptでhtml要素を取得できないエラー

メインビジュアル

javascriptでhtml要素を取得できないエラー

Uncaught TypeError: Cannot set property 'innerHTML' of undefined

上記のようなエラーが出た時の原因と解決方法をご紹介します。

    目次

  1. エラーの内容
  2. エラーの原因
  3. 解決方法その1
  4. 解決方法その2
  5. まとめ

エラーの内容

JavaScriptでhtmlのh1タグを取得して、h1タグ内で"Hello"と表示させるために以下のようなコードを書きました。

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript">
    document.getElementsByTagName("h1")[0].innerHTML = "Hello";
  </script>
</head>
<body>
  <h1></h1>
</body>
</html>

しかしなぜか動かない。。。
そしてコンソールを除いてみると以下のような文言が

Uncaught TypeError: Cannot set property 'innerHTML' of undefined

h1タグは書いてあるのに、なぜundefinedになってしまうのか。原因を探って見ました。

エラーの原因

DOM構築のためのパースはhtmlファイルを上から順に読んでいきます。そのため、scriptタグが読まれている段階ではまだh1タグまでたどり着いていないので、タグを取得できなかったようです。

DOM構築パースの過程

そのため、getElementsByTagName()だけではなく、htmlのタグを取得しようとする同期的なJavaScriptは全てこのエラーが起きるでしょう。

ではどのように解決できるでしょうか

解決方法その1

以下のように</body>のすぐ上にscriptタグを記述することで、標的のタグが読み込まれた後にJavaScriptを発火させることができます。

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <h1></h1>
  <script type="text/javascript">
    document.getElementsByTagName("h1")[0].innerHTML = "Hello";
  </script>
</body>
</html>

この場合、scriptタグが読み込まれる前にh1タグが読み込まれるので、undefinedでは無くなります。ただbodyタグを取得したい場合、この記述では上手く動きません。

解決方法その2

JavaScriptをDOM構築が終わった後に読み込むように書きます(非同期処理)。書き方は色々あります。下記のコードはその一例です。

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript">
    window.onload = function(){
      document.getElementsByTagName("h1")[0].innerHTML = "Hello";
    };
  </script>
</head>
<body>
  <h1></h1>
</body>
</html>

window.onloadを使えば、htmlが全て読み込まれてレイアウトが一旦構築された後に発火させてねと指示することができます。

その他の非同期的読み込みの記述はコチラ

まとめ

このエラーのおかげで、なんとなくDOM構築の際のパースの手順が理解できました。JavaScriptでhtmlの要素に働きかけたい時は、その部分のhtmlが読み込まれた後にjsの処理ができているか確認しましょう。