🚀
【技術書まとめ】改訂3版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで
本書を読んだ目的
現在のJSを体系的に捉えるために本書を手に取った。
印象に残った記述をまとめておく。
1: イントロダクション
- フレームワークとはPCでいうマザーボードのようなもの
- (たとえがわかりやすい)
2: 基本的な書き方
-
<scipt>
要素は何度記述されても最終的にひとまとめで解釈される - 基本型(stringなど)と参照型(object, arrayなど)でデータの扱いが違う
- falsyな値
- 空文字列(""), ゼロ値(0, -0, 0n), null/undefined, NaN
- これ以外はtruthyな値
- 空文字列(""), ゼロ値(0, -0, 0n), null/undefined, NaN
- 数値リテラル
- 整数リテラル
- 0b(2進数)
- 0o(8進数)
- 0x(16進数)
- 浮動小数点リテラル
- 0.1234e4(= 0.1234*10の4乗)
- 数値セパレーターで可読性を高める(1_234_567)
- 整数リテラル
3: 演算子
- 加算演算子(+)以外の演算子はなんとかして数値として処理しようとする
- 小数点を含む演算に注意する
- 0.2 * 3 // 0.6000000000000001となる
- 内部的に2進数で演算しているから
- decimal.jsを使用してもいい
- 0.2 * 3 // 0.6000000000000001となる
- 変数とはメモリ上の場所に対して付けられた名札ともいえる
- 定数は再代入できないだけ
- 配列の中身の書き換えは可能
- 分割代入
const {a, b, c, ...other} = data;
- 必要なものだけ抜き出す
-
==
は緩い等価演算子- 左分/右辺の型がをなんとか等しいと見なせないかと試みる
- typeofで意味のある型を返すのはプリミティブ型だけ
- 配列などの参照系はobjectとなる
4: 制御構文
- ifやforなど
5: 組み込みオブジェクト
- lengthはサロゲートペアに注意する
-
[...str].length
のように文字配列に分解するときちんと認識する
-
- normalizeでUnicode正規化する
- NaNは自分自身を含むすべての値と等しくない
Number.NaN === Number.NaN) // false
- 配列から任意の要素を取り出す
list[Math.floor(Math.random() * list.length)];
- 配列操作図解
- 完全に平坦化するには
list.flat(Infinity)
- Array.fromで配列をコピーするとシャローコピーになる
- 入れ子になっている場合、元配列への修正がコピー先に影響する
- オブジェクトへの参照だけが複製されるから
- 入れ子になっている場合、元配列への修正がコピー先に影響する
- Mapのキーは
===
で比較される
6: 関数
- function命令はスコープの先頭で定義されたとみなされる
- 巻き上げ(hoist)
- 逆に、関数リテラル、アロー関数、Functionコンストラクターは実行時に評価される
- 呼び出しもとコードよりも先に記述する
- スコープの異なる変数は、名前が同一であっても異なる変数と見なされる
7: Objectオブジェクト
- プロトタイプなど
8: オブジェクト指向構文
- クラスの基本など
9: DOM
- DOMとはHTML文書をオブジェクトとして使う仕組み
- マークアップ言語で書かれたドキュメントにアクセスする標準的な仕組み
- 要素ノードを取得する
- idで:
getElementById('result')
- セレクター式で:
querySelector('#list .external')
- セレクター式で複数:
querySelectorAll('#list .external')
- idで:
- 子要素を取得する
- 取得メソッドで特定の要素を取得したあと、近接ノードはノードウォーキングで取得する
- 例: selectタグを取得してから子要素のoptionタグを取得する
- childNodesプロパティで取得する
- 取得メソッドで特定の要素を取得したあと、近接ノードはノードウォーキングで取得する
- イベント駆動型モデル
- イベントの発生を検知して実行する:
addEventListener('mouseenter', ...)
-
<script>
要素の記述位置によって、対象の読み込み前に使用してエラーが起こることがある- 対応方法
-
DOMContentLoaded
イベントリスナーでくくる - defer属性をつける
- ページロード/解析を終えたタイミングでコードを実行する
-
- 対応方法
- イベントの発生を検知して実行する:
- 属性値を取得する
getAttribute('title')
- すべて取得する:
img.attributes
- NamedNodeMapとして返す
- ノードの順序は保証されない
- NamedNodeMapとして返す
- 属性値を設定する
setAttribute('src', 'images/noimage.jpg')
-
hasAttribute('src')
で属性の存在を確認できる
- 要素のプロパティを取得/設定する
- querySelectorで取得した
member.value
は現在の値だが、member.getAttribute('value')
で取得した値は初期値となる
- querySelectorで取得した
- テキストを取得/設定する
-
.textContent
を使う - 入力値をそのままinnerHTMLで使うと、クロスサイトスクリプティング(XSS)脆弱性となる
-
- フォーム要素にアクセスする
-
selectタグ.value
等で取得できる- 複数選択可であれば
selected
になっているものの値を取得する
- 複数選択可であれば
- ラジオボタン/チェックボックスでは、inputタグが
checked
になっているものの値を取得する
-
- アップロードされたファイルの情報を取得する
- おもなプロパティは
name, type, size, lastModified
- FileReaderを使用して読み込める
- バイナリを読み込む:
readAsDataURL()
- バイナリを読み込む:
- おもなプロパティは
- ノードを追加/置き換え/削除する
- 追加など
- 作成:
createElement()
- 追加:
append()
- 属性の作成:
createAttribute()
- 属性の追加:
setAttributeNode()
- テキストノードの作成:
createTextNode()
- 要素を挿入先の子要素の先頭に追加する:
prepend()
- 要素を挿入先の前に追加する:
before()
- 要素の挿入先の末尾に追加する:
after()
- 作成:
- ulにliをappendしていくと、その度に再描画されてしまう
- DocumentFragmentオブジェクト上で組み立ててからappendする
document.createDocumentFragment()
- DocumentFragmentオブジェクト上で組み立ててからappendする
- data-xxxx属性でイベントリスナーで使用するパラメーターを埋め込める
- HTMLCollection/NodeListは文書ツリーを参照しているため、リアルタイムに変更が反映される
- 追加など
- イベントオブジェクトの基本
- イベントオブジェクトのメンバー
- 一般: target, currentTarget, type(click等)など
- 座標: clientX, screenX, pageX, offsetXなど
- キーボード/マウス: button, key, shiftKeyなど
- イベント処理をキャンセルする
- バブリングをキャンセルする:
e.stopPropagation()
- バブリングを直ちにキャンセルする:
e.stopImmediatePropagation()
- 同じ要素のイベントリスナーも実行しない
- イベント本来の挙動をキャンセルする:
e.preventDefault()
-
cancelable
なイベントだけキャンセル可能
-
- バブリングをキャンセルする:
- data-xxxx属性は
element.dataset.prop
でも操作できる- 例:
<input ... data-add="1"/>
をinput.dataset.add = 2
でセットする
- 例:
- currentTargetはイベントリスナーが登録された要素を常に取得する
- targetはイベントの発生元を取得する
- イベントの動作オプションを指定する
- 初回イベントだけを処理する:
{ once: true }
- 初回イベントだけを処理する:
- asyncとdeferの違い
- asyncはページ解析を待たずにダウンロードでき次第、実行する
- integrity属性はコードの改ざんを防ぐ
- イベントオブジェクトのメンバー
10: クライアントサイドJavaScript開発を極める
- ブラウザーオブジェクトの階層構造
- タイマー機能 setInterval, setTimeout
- あくまで指定された時間にキューに処理を登録するだけ
- シングルスレッド処理だから
- 正確な時間とは限らない
- あくまで指定された時間にキューに処理を登録するだけ
- ウィンドウサイズ
- スクロール位置を設定/取得する
- 指定位置までスクロール(絶対座標):
scrollTo(x, y)
- 指定位置までスクロール(絶対座標):
- 表示ページのアドレス情報を取得/操作する locationオブジェクト
- locationオブジェクト
- hash:
#gihyo
- host:
wings.msn.to:8080
- hostname:
wings.msn.to
- pathname:
/js/sample.html
- search:
?id=12345
- hash:
-
href
プロパティで移動すると履歴が残る(戻るボタンで戻れる)- 履歴を残したくない場合は
replace
メソッドを使う -
assign
メソッドは、実行元コードと操作先のオリジン(プロトコル://ドメイン:ポート)が違う場合にアクセスをガードする
- 履歴を残したくない場合は
- locationオブジェクト
- 履歴に沿ってページを前後に移動する historyオブジェクト
-history.back(), history.forward()
- JSによる操作をブラウザーの履歴に残す
- pushStateメソッド
- History APIとも呼ばれる
- pushStateメソッド
- 便利なログメソッド
- スクリプトの実行時間を計測する:
console.time()
- オブジェクトを見やすい形式で出力する:
console.dir()
- スクリプトの実行時間を計測する:
- ユーザーデータを保存する Storageオブジェクト
- ローカルストレージ: オリジン単位でデータを管理する。
- ウィンドウ/タブを跨いでデータの共有が可能
- ほかのホストの保存データを読み出すことはできない
- 明示的にデータを削除しないとデータが消えない
- 同一オリジンで複数アプリを稼働していると変数名が衝突しやすい
- ウィンドウ/タブを跨いでデータの共有が可能
- セッションストレージ: 現在のセッション(ブラウザーが開いている間)でだけ維持されるデータを管理する
- ウィンドウ/タブ間でデータを共有することはできない
- オブジェクトをストレージに保存する場合は復元可能なJSON化する
- 保存:
storage.setItem('apple', JSON.stringify(apple));
- 読み取り:
JSON.parse(storage.getItem('apple'));
- 保存:
- storageイベントリスナー
- key: 変更されたキー
- oldValue: 変更前の値
- newValue: 変更後の値
- url: 変更発生元のページ
- storageArea: 影響受けたストレージ(localStorage/sessionStorage)
- ローカルストレージ: オリジン単位でデータを管理する。
- Fetch API
- Responseオブジェクト
- ステータス
- ok: 成功したか
- status: HTTPステータスコード
- ヘッダー
- headers: Headersオブジェクト
- type: レスポンスタイプ
- 本文
- body: レスポンス本体を取得(ReadableStreamオブジェクト)
- blob(): Blobとして取得
- json(): JSONとして取得
- ステータス
- fetchは404などの問題をエラーとはみなさない
-
res.ok
で200番台のコードが返されているかを確認する必要がある
-
- クエリ情報はURLSearchParamsオブジェクトで組み立てる
-
params.toString()
で使用する- 自動的にエスケープ処理される
-
- POSTデータはFormDataオブジェクトで組み立てる
- append: 名前name、値valueでフィールドを追加する
- entries: すべてのキー/値を取得する
- getAll(name): 指定の名前のフィールドをすべて取得する
- Responseオブジェクト
- 異なるオリジンにアクセスする
- CORS
- サーバー側のコードからオリジンをまたぐのはエラーとならない
- CORS
- Promiseオブジェクト
- Promiseの状態管理
- Promiseの状態管理
- Web Worker
- JSによる処理をマルチスレッド化するための仕組み
- ワーカーはバックグラウンドで動作するJSコードのこと
- postMessage()でパラメーターを送信する
- messageイベントリスナーで結果を処理する
- ワーカーはバックグラウンドで動作するJSコードのこと
- 高度の数学計算などCPUを占有するような処理はWeb Workerを利用する
- ワーカーではDOMツリーを操作できない
- JSによる処理をマルチスレッド化するための仕組み
11: 現場で避けて通れない応用知識
- Vite, ESlint, JSDocなど
Discussion