JavaScript
JavaScriptとは
JavaScriptは、ブラウザ上で動作する標準のプログラミング言語です。[[HTML]] と [[CSS]] で作られた静的なページに、クリックへの反応・データの取得・画面の書き換えといった動きを加えます。
const button = document.querySelector('#greet')
button.addEventListener('click', () => {
alert('こんにちは!')
})
初学者向けポイント
- DOM操作 = HTMLをプログラムから読み書きすること。上の例の
querySelectorがそれ - 非同期処理(Promise / async-await)が重要。サーバーとの通信([[fetchと非同期通信]])は「待つ」処理になるため
- ブラウザの外でも [[Node.js]] を使えばサーバーサイドやCLIツールも書ける
言語の特徴
| 特徴 | 説明 |
|---|---|
| 動的型付け | 変数の型を宣言しない。柔軟だが実行時エラーの原因にも([[TypeScript]] で補える) |
| プロトタイプベース | クラス構文もあるが、内部はプロトタイプ継承 |
| イベント駆動 | クリックや通信完了などの「イベント」に反応して動く |
| シングルスレッド | イベントループで非同期処理を捌く |
つまずきやすい3つの点
JavaScript は書き始めるのが速い反面、「動いてはいるが意図と違う」状態に入りやすい言語です。最初に踏みやすい3つを挙げます。
1. 比較には === を使う
== は比較の前に型をそろえようとするため、直感に反する結果を返します。
'1' == 1 // true ← 文字列と数値が「等しい」
0 == false // true
'1' === 1 // false ← 型が違えば必ず false
変換規則を覚えるより、常に === を使うと決めるのが定石です。同じく if (value) では 0・空文字・null・undefined・NaN が偽になり、「件数が0のときだけ表示が消える」というバグの多くはここから生まれます。
2. 変数は const から書き始める
var は書いた場所に関わらず関数全体に漏れる古い宣言で、現在は使いません。let と const は {} の内側でだけ有効です。まず const で書き、再代入が必要な変数だけ let に変えると、「この値は途中で変わらない」と一目で判断できます。なお const が禁じるのは変数への再代入だけなので、const list = [] の中身は list.push(1) で変えられます。
3. オブジェクトと配列は「参照」で渡る
const a = { count: 0 }
const b = a
b.count = 1
console.log(a.count) // 1 ← a も変わっている
数値や文字列は値がコピーされますが、オブジェクトと配列は同じ実体を指す名札が増えるだけです。「コピーしたつもりが元データを壊していた」事故はほぼこれが原因で、別物にしたいときは { ...a } や [...list] のように展開してコピーを作ります。
シングルスレッドと非同期
JavaScript は一度に1つの処理しか実行しない言語です。画面の描画もクリックへの反応も同じ1本の流れで順に処理されるため、重い計算を回している間は操作を受け付けられず、画面が固まって見えます。
そこで通信やタイマーのような「待ち」は、結果を後で受け取る約束(Promise)として扱い、待つ間は制御を他へ譲ります。async / await はそれを同期的な見た目に整えた書き方です。最初に踏みやすいのは、結果が届く前に値を使ってしまう誤りです。
let user
fetch('/api/me').then((res) => res.json()).then((data) => { user = data })
console.log(user) // undefined ← 通信はまだ終わっていない
console.log は通信の完了を待たずに実行されるため undefined になります。値を使うコードは、必ず結果が届いた後(await の後や then の中)に置きます。非同期の設計は [[並行処理と非同期]]、fetch 特有の落とし穴は [[fetchと非同期通信]] にあります。
エコシステム
npm には世界最大級のパッケージ資産があり、[[React]] のようなUIライブラリ、[[Vite]] のようなビルドツールもすべて JavaScript(または [[TypeScript]])で書かれています。
次に読む記事の地図
JavaScript は多くの技術の入口です。いま何をしたいかで次の1本を選んでください。
- ブラウザを操作する — 書き換える対象そのものが [[DOM]] です。それが画面に出るまでの流れは [[ブラウザレンダリングの仕組み]] にあり、「なぜ大量のDOM操作が重いのか」が腑に落ちます。ブラウザ側にデータを残すなら [[WebストレージとCookie]] へ。
- サーバーとやり取りする — 通信の入口が [[fetchと非同期通信]]、データの形式が [[JSON]]。同じ言語でサーバー側も書きたくなったら [[Node.js]] へ。
- 配れる形にまとめる — コードを分割する標準の仕組みが [[ESモジュールとバンドラ]]、他人のコードを取り込む仕組みが [[npmとパッケージ管理]]。古い環境への対応は [[トランスパイルとポリフィル]] へ。
- 大きな画面を作る — 手作業のDOM操作が限界に来たら [[React]] や [[Vue.js]] へ。どちらを選んでも効いてくるのが [[状態管理]] の考え方です。標準機能だけで部品化する道もあります([[Web Components]])。
- 壊さない・重くしない — 受け取った文字列をそのままHTMLに差し込む書き方は [[XSS(クロスサイトスクリプティング)]] の直接の原因です(全体像は [[Webセキュリティ]])。入力やスクロールのたびに処理が走って重い、という詰まりは [[デバウンスとスロットル]] で解けます。
- さらに先へ — オフライン動作を扱う [[PWA]]、重い計算をバイナリに任せる [[WebAssembly]] も JavaScript から呼び出して使います。
関連技術とのつながり
- [[TypeScript]] — JavaScriptに型を追加した上位互換言語
- [[Node.js]] — ブラウザ外でJavaScriptを動かす実行環境
- [[React]] — JavaScriptでUIを構築する代表的ライブラリ
- [[HTML]] / [[CSS]] — JavaScriptが操作する対象
Q: 本文が勧めている等価比較の書き方はどれ?
- [x] 型変換を伴わない `===` を常に使う
- [ ] 型をそろえてくれる `==` を常に使う
- [ ] 場面に応じて `==` と `===` を使い分ける
解説: `==` は比較の前に型をそろえるため `'1' == 1` が true になるなど直感に反します。変換規則を覚えるより常に `===` を使うのが定石です。
Q: `const a = { count: 0 }` のあとに `const b = a; b.count = 1` を実行すると `a.count` はどうなる?
- [ ] 0 のまま変わらない
- [x] 1 に変わっている
- [ ] エラーになって代入できない
解説: オブジェクトと配列は同じ実体を指す名札が増えるだけなので、b 経由の変更が a にも見えます。別物にしたいときは `{ ...a }` などでコピーを作ります。
Q: JavaScriptがシングルスレッドであることの帰結として本文が挙げているのはどれ?
- [ ] 通信中は他のタブも一緒に止まる
- [x] 重い計算を回している間はクリックに反応できず画面が固まって見える
- [ ] 変数の型が実行中に変わらなくなる
解説: 描画もイベント処理も同じ1本の流れで順番に処理されるため、重い処理でそこを占有すると操作を受け付けられなくなります。