About

JavaScriptガイド

言語内部、ランタイム、フレームワーク — コードレベルで動作原理整理

言語内部

イベントループ — setTimeout(fn, 0)が即座に実行されない理由

Call Stack、Task Queue、Microtask Queueの実行順序

JavaScriptはシングルスレッドなのに非同期が可能な理由:イベントループがCall Stackが空の時にTask Queueからコールバックを取り出して実行するから。Promiseのthenは Microtask Queueに入り通常Taskより先に実行される。

クロージャとスコープチェーン — 関数が外部変数を記憶する原理

Lexical Environmentオブジェクトが作るスコープチェーンの内部構造

クロージャは関数が生成された時点のLexical Environmentをキャプチャして保存するもの。関数が外部スコープの変数を参照すると、そのLexical Environmentオブジェクトがガベージコレクションされず生き残る。

プロトタイプチェーン — classがなかった時代の継承

__proto__、prototype、Object.create()の関係

JavaScriptのclassはシンタクティックシュガー。内部的にプロトタイプチェーンで動作する。オブジェクトの__proto__が親オブジェクトを指し、プロパティが見つからなければチェーンを辿り上がる。

Promise内部 — then()がMicrotask Queueに入る過程

Promiseの3つの状態とthenableチェーンの実行メカニズム

Promiseはpending/fulfilled/rejectedの3状態を持つ状態マシン。resolve()呼び出し時にthenに登録されたコールバックがMicrotask Queueに入る。async/awaitはPromiseのシンタクティックシュガー。

ブラウザAPI

Web Workers — JavaScriptでマルチスレッドを使う方法

postMessageの構造化複製(Structured Clone)とSharedArrayBuffer

Web Workerはメインスレッドと別のスレッドでJavaScriptを実行する。DOMアクセス不可、postMessageで通信。重い計算をWorkerに回せばUIが止まらない。

Service Workerライフサイクル — install、activate、fetchの順序

PWAの核心、オフラインキャッシュが動作するメカニズム

Service Workerはブラウザとネットワークの間にプロキシとして動作する。install→activate→fetchの順でライフサイクルが進行し、Cache APIでリソースを保存してオフラインでもアプリが動作するようにする。

Intersection Observer — スクロールイベントなしで要素の可視性を検出

lazy loading、無限スクロール、アニメーショントリガーの高性能実装方法

Intersection Observerは要素がビューポートに入る/出る時にコールバックを実行する。scrollイベント+getBoundingClientRect()より性能が良く、ブラウザが最適化されたタイミングで実行。

Popover APIとは?JSなしでツールチップを開閉する方法

popover属性1つで開閉・Escキー・アクセシビリティが自動動作するブラウザネイティブUI

従来のツールチップにはイベントリスナー、状態管理、ARIA属性の手動同期が全て必要だった。Popover APIはこれをブラウザネイティブで置き換える。popover属性とpopovertargetだけで開閉・Escキー・キーボードナビゲーションが自動動作。

Cookie・localStorage・sessionStorage — 三つの質問で決まる

同じ画面でフォルダツリーはCookie、スクロール位置はsessionStorageに分かれた理由

サーバーが読むか、最初のHTMLに反映が必要か、タブを閉じても残すか。この順に聞けばほぼ決まる。トークンのような秘密値は質問せずHttpOnly Cookieへ。

event.target vs currentTarget — アイコンの線の上を押した時だけ起きるバグ

data-* を読むならcurrentTarget。SVGは塗られた線だけがクリックを受ける

リスナーを付けた要素のdata-*を読むならevent.currentTargetを使う。event.targetは実際に押された一番内側の要素なので、ボタン内のSVGアイコンの線を押すと<path>が取れて値がundefinedになる。

Web Audio

setIntervalでドラムを鳴らすとリズムが揺れる — 「今鳴らせ」ではなく「何秒に鳴らせ」

JSタイマーは起こすだけ、音はオーディオの時計で予約するlookaheadスケジューラ

ブラウザでリズムを合わせるなら、タイマーのコールバック内ですぐ音を出さず、25msごとに起きて0.1秒先までの音をAudioContextの時刻で予約する。同じ妨害条件でsetIntervalは114〜136msで揺れ、予約方式は0.5秒間隔のままだった。

イヤホンの「左だけ」は二種類 — StereoPanner(寄せる)とChannelSplitter(選ぶ)

pan: -1は右の音を捨てずに左へ合わせる。実測で見た違い

イヤホンは受け取ったL/Rを鳴らすだけ。Webで「左だけ」を作るとき、StereoPannerNodeのpan: -1は右の音を左へ寄せ、ChannelSplitterは左チャンネルだけを選んで右を捨てる。どちらも右は無音だが、左で何が聞こえるかが違う。

オーディオのテストは画面ではなくAnalyserNodeで — バックグラウンドタブで17個すべて「無音」と出た理由

絵は止まっても音は鳴る。ピーク値を測ればクリッピングまで見つかる

ブラウザ自動化でオーディオデモを検査するときにキャンバスの波形を見ると、バックグラウンドタブではrequestAnimationFrameが止まり、全部無音と誤判定する。AnalyserNodeの時間領域データからピークを測れば、音の有無とクリッピング(1超え)の両方がわかる。実際にクリッピングを3件見つけた。

Strudelはビートのスケッチには最強、曲の完成には弱い — そしてlazy importするとエフェクトが静かに消える

アプリに組み込んで使った感想と、「次のmousedown」を待つオーディオ初期化の罠

Strudelはループをその場でいじるのは強いが、曲を最後まで作ったりサービスに組み込んだりするのは弱い。アプリに入れるときバンドル(約659KB)が大きいのでクリック時にdynamic importしたら、オーディオ初期化がすでに過ぎたmousedownを待ち続け、shapeのようなAudioWorkletエフェクトがエラー表示なしに抜けた。mousedownを自分で一度発火させれば直る。

オープンソース分析

background-removal-jsとは?ブラウザだけで画像の背景を削除して透明PNGにする仕組み

IS-Net ONNXモデル + WASM推論 + Canvas API、サーバーなしでクライアント完結するパイプライン

background-removal-js(imgly)は、画像の背景を削除して透明PNGで返すJavaScriptライブラリ。IS-NetモデルをONNX Runtime WASMでブラウザ内実行するので、画像をサーバーに送らない。デコードからPNG出力までの5段階をコードで追う。

OpenGenerativeUI — ClaudeのVisual Artifactsをオープンソースで再現した構造

CopilotKit Deep Agents + LangGraph + サンドボックスiframe、AIがチャート・3D・ダイアグラムをリアルタイム生成するパイプライン

CopilotKitがClaudeのインタラクティブVisual Artifacts生成をオープンソースで実装した。Next.js 16フロントエンド + Python LangGraphエージェントがHTML/SVG/Chart.js/Three.jsコードを生成、サンドボックスiframeでレンダリング。MITライセンス。Star 1.1K。

Pretext — DOMなしでテキスト高さを測定する純粋JSレイアウトライブラリ

Canvas measureText()で文字幅を取得し、行計算は純粋な算術演算のみ — レイアウトリフロー0

ブラウザでテキストが何行になるか調べるには通常getBoundingClientRectやoffsetHeightを使うが、これはレイアウトリフローを強制する。PretextはCanvas measureText()でフォントエンジンから直接文字幅を取得し、行計算はキャッシュされた幅値での純粋な算術演算のみ。DOM一切アクセスなし。500テキストバッチでlayout()が0.09ms。React・Relay創始者chenglou氏のプロジェクト。⭐ 7.1K。