お世話になります。 まず解決法からですが、
1.window.addEventListener("load", () => {行いたい処理})
と変更
2.操作したい要素の後にJavaScriptの記載する
かなと思います 個人的には1番目がおすすめです。
以下解説
まず全体としてなぜうまくいかないのか
<button id="btn">表示</button>
の生成前に
let btn = document.getElementById('btn')
が実行されてしまっているからです。
DOM要素のパース(処理)中にJavaScriptも実行されており、
<button id="btn">表示</button>
のパース前に
let btn = document.getElementById('btn')
が実行されてしまったわけです。
そうすると、document.getElementById('btn')
には何も存在しない(null)のため
btnはnullとなり、後続の、btn.addEventListener
がエラーを起こします。
このときのエラーが
Cannot read properties of null (reading 'addEventListener')
となります(properties of null つまり 内容が存在しない)
解決法
1.パースが終わるまで待つ
2.必要要素のパース完了後にJavaScriptを実行する
1.についてはまずwindowの内容(これにはDOM要素が含まれています)
が読み込まれてから内部の関数を実行します。
そのため、<button id="btn">表示</button>
の存在が保証され
let btn = document.getElementById('btn')
が正常に動きます
DOM要素全部用意できてから、内部の関数を実行してね ということです
2.についてはHTMLというのは記載順(上から下)にパースされます
そのため必要要素のパースが完了しているので
必然的に let btn = document.getElementById('btn')
が正常に動きます
関数を実行時には対象の要素があるぞ というわけです