質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

1226閲覧

<script>の記入する位置について

susumu-99

総合スコア44

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

1クリップ

投稿2022/11/12 04:59

お世話になります。

HTMLファイルでJavaScriptの<scripnt>の書く位置について分からないことがあり質問させていただきました。

以下のコードはボタンのクリックでasideを開閉させるために作ったものです。
これはスムーズに動きます。

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 <style> 9 #a_and_aside{ 10 display: flex; 11 } 12 aside{ 13 width: 0px; 14 height: 600px; 15 border: 1px solid #000; 16 transition: all 0.5s; 17 overflow: hidden; 18 } 19 aside.aside_open{ 20 width: 200px; 21 } 22 .btn01{ 23 display: block; 24 position: relative; 25 width: 200px; 26 height: 50px; 27 border: 1px solid #000; 28 text-decoration: none; 29 } 30 </style> 31//①<style>終了後 32</head> 33<body> 34//②<body>タグの直後 35 <div id="a_and_aside"> 36 <aside>test</aside> 37 <a href="#" class="btn01"> 38 このボタンでasideが開く 39 </a> 40 </div> 41 42 <script>//この<script>~</script>を、 43 const aside = document.querySelector('aside'); 44 const btn01 = document.querySelector('.btn01'); 45 46 btn01.addEventListener('click', 47 function(){ 48 aside.classList.toggle('aside_open'); 49 } 50 ); 51 </script> 52 53</body> 54</html>

質問はこの<script></script>の位置を①<style>終了後 や、②<body>タグの直後 に移動するとJavaScriptが動作しなくなり、コンソールのエラーが
『Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')』と表示されます。
私は今までJavaScriptは①<style>終了後 や、②<body>タグの直後 に書いても動作すると思っていました。また、今調べたサイトでも<script>の位置によって動作しなくなるといったものは見つけられませんでした。
書く位置によって動作しなくなる場合があるのでしょうか?

どなたかこの挙動の理由が分かる方、回答よろしくお願いしますm(__)m

draqを押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/12 08:47

この質問の回答をして分かったことを自分用のメモ書きとして、また同じような疑問をもってこの質問にたどりついた方の少しでもお役に立てるように、いただいた回答をもとに自分なりにまとめておきます。 私はJavaScriptの知識が浅いため間違っている箇所があるかもしれません。 もし間違い等があればご指導いただけるとありがたいです。 ・DOMに関する<script>(JavaScript)を書く位置 (1) DOM解析が終わった</body>(ボディの直前) (2) JSを別ファイルに書いて<head>内に<script scr=”…”>の形をとっても<body>解析前に読み取るためエラーが発生する。<body>直後も同様 (3) <script scr=”…”>、<body>直後に書くのであれば、 window.addEventListener('DOMContentLoaded', (){…});とするか、 外部JSファイルを読み込む形式の場合は、 <script src="script.js" defer> とする。 ・また『Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')』のエラーは、bodyを読み込む前なので、プロパティがnullの状態であり、nullには.addEventListenerは使えないこと示すものとのことでした。 以上です。回答をいただいたみなさま方ありがとうございました。
guest

回答3

0

const btn01 = document.querySelector('.btn01');

ここですがhtmlのDOMツリーの解析が完了するまえに呼び出すとnullが返ります。
このためbodyの最後にscriptタグを置くか、scriptタグにdefer属性を設定すればよいかと思います。

投稿2022/11/12 06:41

a.com

総合スコア871

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/12 08:14

回答ありがとうございます。 どこに書いてもいいという思い込みをしていました。 丁寧な解説ありがとうございました!
guest

0

HTML・JS含め、プログラムは基本的に上から順番に読み込まれて実行されます。

エラーになる例

html

1<head> 2 <script> 3 const btn = document.querySelector('#btn'); // ①実行→null 4 btn.addEventListener('click', () => console.log('ボタンがクリックされました')); // ②nullにイベントつけられないのでエラー 5 </script> 6</head> 7 8<body> 9 <button id="btn">ボタン</button> <!-- ③ボタン読み込み --> 10</body>

html

1<head> 2</head> 3 4<body> 5 <script> 6 const btn = document.querySelector('#btn'); // ①実行→null 7 btn.addEventListener('click', () => console.log('ボタンがクリックされました')); // ②nullにイベントつけられないのでエラー 8 </script> 9 10 <button id="btn">ボタン</button> <!-- ③ボタン読み込み --> 11</body>

いずれの場合も、①でボタン要素を取得する処理を実行していますが、①の行の時点ではまだページ読み込み処理は③の行に到達していません。
(上から順番に読み込まれ実行されていくので当然ですが)

ですので①ではnullが取得され(戻され)ます。
(ページは、まだ③のボタン要素が存在することを知らないので、そんな要素ないよーってなります)
nullには.addEventListener()は使えませんのでエラーとなります。

正しい例

ボタン要素が取得されてから、JSが実行されるような順番にコードを書く必要があります。

実行コードを物理的に後ろにかく

html

1<head> 2</head> 3 4<body> 5 <button id="btn">ボタン</button> <!-- ①読み込み --> 6 7 <script> 8 const btn = document.querySelector('#btn'); // ②実行 9 btn.addEventListener('click', () => console.log('ボタンがクリックされました')); // ③実行 10 </script> 11</body>

プログラムは上から順番に読み込まれ実行されるわけですから、物理的に、ボタン要素より後の行数にJSのコードを書けば、ボタン要素が読み込まれたあとにJSが実行されますから、うまくいきます。

イベントリスナーでページ読み込み後にJSを実行させる

window.addEventListener()'DOMContentLoaded''load'イベントを使えば、ページが読み込まれた後にJSが実行されるよう強制することができます。

html

1<head> 2 <script> 3 window.addEventListener('DOMContentLoaded', () => { // ①スキップ 4 const btn = document.querySelector('#btn'); // ④実行 5 btn.addEventListener('click', () => console.log('ボタンがクリックされました')); // ⑤実行 6 }); 7 </script> 8</head> 9 10<body> 11 <button id="btn">ボタン</button> <!-- ②読み込み --> 12</body> 13<!-- ③ページ全部読み込めたらスキップしたところに戻る -->

以上いずれの例も、例通りhtmlファイルの中で<script>JSコードを書く</script>という形式でも、<script src="script.js"></script>と外部JSを読み込む形式でも、どちらでもかまいません。


defer属性をかいてページ読み込み後にJSを実行させる

こちらの方法は、外部JSファイルを読み込む形式のみです。

html

1<head> 2 <!-- ①スキップ --> 3 <script src="script.js" defer></script> 4</head> 5<body> 6 <!-- ②読み込み --> 7 <button id="btn">ボタン</button> 8</body> 9<!-- ③ページ全部読み込めたらスキップしたところに戻る -->

javascript:script.js

1const btn = document.querySelector('#btn'); // ④実行 2btn.addEventListener('click', () => console.log('ボタンがクリックされました')); // ⑤実行

以上代表例をご紹介しました。


他の方の回答のコメント欄より質問者様のご質問を引用させていただきます。

「headに置くスクリプトは、ドキュメントの読み込みが終わったイベントで処理を行うことが一般的です。」であれば、headに書けばJavaScriptが動作すると思っていいですよね。

いいえ違います。<head>の中に書いたら、JSが後から実行されるというわけではありません。

今までこんなことはなかったのに、コードの書き方が悪いのでしょうか?

今までとは、ご自身の書いたコードのことでしょうか?
それともどこかからコピペしてきたり、プラグインで提供されているコードを利用したときのことでしょうか?

おそらく後者のことだと思うのですが、これらのコードは「要素・ページが読み込まれた後にJSを実行する」ようにきちんとコードが書かれています。
ですので、headの中に書こうがbodyの閉じタグ直前に書こうが、どこに書こうとも問題がなかったわけです。

投稿2022/11/12 07:47

編集2022/11/12 07:48
Cocode

総合スコア2314

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/12 08:12

回答ありがとうございます。 たしかにそうでした。 JavaScriptを勉強を始めた頃ドットインストールを使用していましたが、ドットインストールでもDOMのscriptは</body>の直前に<script>のコードを書いていました。 自分の思い違いですね。 分かりやすい解説ありがとうございましたm(__)m
guest

0

ベストアンサー

位置と書き方によってはあります。
基本は上から読み込まれ、実行コードがあればそのまま実行されます。
実行されたときにhtml上でまだ読み込まれてない要素を参照しようとしている場合に当該現象が置きます。

どこに置いても参照できるようにするためには、「コンテンツ読み込み後」のイベントをaddEventListenerで捕捉します。

投稿2022/11/12 05:10

m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/12 05:23

回答ありがとうございます。 書き方によっては…ということは、この<script>の書き方を変えると①<style>終了後 や、②<body>タグの直後においてもちゃんと動くようにできる書き方もあるということでしょうか? 質問重ねてすいません。
susumu-99

2022/11/12 05:31

今JavaScriptを別ファイルとして、<head>内に<script src="…">という形で入れてみました。 やっぱり動かないものですね(´;ω;`) 今までこんなことはなかったのに、コードの書き方が悪いのでしょうか? それともそういうものなのでしょうか
susumu-99

2022/11/12 06:02

回答ありがとうございます。 「headに置くスクリプトは、ドキュメントの読み込みが終わったイベントで処理を行うことが一般的です。」であれば、headに書けばJavaScriptが動作すると思っていいですよね。 やはり私のコードがまちがっているのでしょうか?
kairi003

2022/11/12 07:49 編集

「ドキュメントの読み込みが終わったイベントで処理を行うこと」をしていないということですね。勝手にされるのではなく自分で書く必要があります。 またはsrc読み込みならdefer属性をつければ自動的にドキュメント読み込み後の実行になります。
m.ts10806

2022/11/12 08:07

ku__ra__geさん、kairi003さん フォローコメントありがとうございます。 susumu-99さん >headに書けばJavaScriptが動作すると思っていいですよね。 表現の誤りかと思いますが、「動作しない」ということはないです。 「動作した結果、エラーとなっている(今回の場合だと要素の読み込みが失敗する)」ということです。 なるべく「うまくいく、いかない、動作する、しない」ではなく「起きている現象」を説明する癖をつけてもらえると、スムーズに技術的なコミュニケーションが取れると思います。 https://teratail.com/help/question-tips#questionTips34 ちなみにheadはHTML内ではほぼ最初にある要素なので、「(JavaScript等による)読み込みを待って動作するイベント」が実装されていない状態だとbody内のどの要素も読み込みは行われないので、Cannot read properties of null となります。
susumu-99

2022/11/12 08:20

「うまくいく、いかない、動作する、しない」ではなく「起きている現象」を説明するようにします。 (この場合だったら「ボタンをクリックしても<aside>が開かない」と書く方が伝わりやすいということですね!) 皆様ありがとうございました。どの回答も大変ありがたかったですが、1番最初にただいたこちらの回答をベストアンサーにさせていただきたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問