React や Vue などのフレームワークを使わず、ブラウザ標準のJavaScriptだけで書くとき(いわゆるバニラJS)に毎回調べがちな構文をまとめました。非同期処理・配列操作・オブジェクトコピー・DOM操作・ストレージなど、実務でよく使うパターンを用途別に整理しています。Node.js でも動く構文は多いですが、主にブラウザ環境を想定しています。
ストレージ — sessionStorage / localStorage
sessionStorage.setItem('myData', '保存したい内容'); // 保存
const savedData = sessionStorage.getItem('myData'); // 読み出す
sessionStorage.removeItem('myData'); // 削除
sessionStorage.clear(); // 全て削除
sessionStorage は同一タブ内でのみ保持され、タブを閉じると破棄されます。最大容量はブラウザによりますがおおむね5MB。保存形式は文字列のみなので、オブジェクトを保存したい場合は JSON.stringify() で変換が必要です。
sessionStorage を localStorage に書き換えるとデータを永続化できます。
オブジェクトの凍結 — Object.freeze
const Trial = {
ok: true,
ng: false
};
Object.freeze(Trial); // オブジェクトを凍結
Trial.ok = false; // 非 strict mode ではエラーにならないが値は変わらない(strict mode では TypeError)
console.log(Trial.ok); // true
const ではプロパティの書き換えを防げません。Object.freeze() はトップレベルのプロパティ変更を防ぎますが、浅い凍結なので入れ子のオブジェクトは変更できます。JS で Enum を表現したいときに便利です。
非同期処理 — fetch / async / await
async function fetchUser(userId) {
const response = await fetch(`/api/user/${userId}`);
if (!response.ok) throw new Error("通信エラー");
const data = await response.json();
return data;
}
fetchUser(1).then(user => {
console.log(user.name);
}).catch(err => {
console.error(err);
});
fetch() はブラウザ組み込みのHTTP通信APIです。await で非同期処理の完了を待てるため、Promise のチェーンよりも読みやすくなります。await を使う関数は async で宣言する必要があります。
非同期処理 — Promise
function wait(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(`${ms}ms 待ちました`), ms);
});
}
wait(1000).then(msg => console.log(msg));
Promise は非同期処理の結果を表すオブジェクトです。resolve で成功、reject で失敗を返します。then を数珠繋ぎにすることで順次処理を書けます。
配列操作 — filter / map
const nums = [1, 2, 3, 4, 5];
const even = nums.filter(n => n % 2 === 0); // [2, 4]
const squared = nums.map(n => n * n); // [1, 4, 9, 16, 25]
console.log(even, squared);
filter と map は配列を加工するメソッドです。for文を使わずワンライナーで処理を書けるのが魅力です。
配列の条件チェック — every / some
// every: 全ての要素が条件を満たすか?
const allPositive = [1, 2, 3].every(n => n > 0); // true
// some: 一つでも条件を満たせばOK
const hasNegative = [1, -2, 3].some(n => n < 0); // true
filter と違い、真偽値だけを返すメソッドです。バリデーション処理などに使えます。
展開 — スプレッド構文 ...
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b]; // [1, 2, 3, 4]
... のスプレッド構文で配列やオブジェクトを展開できます。Object.assign と同様に浅いコピーを作るのにも使えます。
オブジェクト結合・クローン — Object.assign
// マージ
const a = { x: 1 }, b = { y: 2 };
Object.assign(a, b); // a は { x:1, y:2 } に上書きされる
// デフォルト適用(後ろが優先)
const opts = Object.assign({ timeout: 5000, retry: 0 }, userOpts);
// 浅いクローン(target を {} に)
const clone = Object.assign({}, source);
Object.assign(target, ...sources) は列挙可能なプロパティを左から右へ浅くコピーし、target を破壊的に更新して返します。浅いマージ・浅いクローン用途ではスプレッド構文でも似た書き方ができます(ただし Object.assign は setter を呼ぶなど挙動が完全一致するわけではありません)。
const merged = { ...a, ...b };
const clone2 = { ...source };
浅いコピーでは、入れ子のオブジェクトは参照が共有される点に注意してください。
深いコピー — structuredClone
const src = { a: 1, d: new Date(), m: new Map([['k', 1]]) };
const dst = structuredClone(src);
ブラウザ/Node 組み込みの深いコピーAPIです。入れ子のオブジェクトまで独立したコピーを作ります。ただし関数・DOM ノード・WeakMap など clone できない値を含む場合は DataCloneError になります。
// 浅いコピー: 入れ子の参照が共有される
const src1 = { nest: { x: 1 } };
const shallow = { ...src1 };
shallow.nest.x = 9;
console.log(src1.nest.x); // 9 ← 参照が共有されるため元も変わる
// 深いコピー: 完全に独立
const src2 = { nest: { x: 1 } };
const deep = structuredClone(src2);
deep.nest.x = 7;
console.log(src2.nest.x); // 1 ← 独立しているため元は変わらない
マージや浅い複製には Object.assign / スプレッド、完全な複製には structuredClone を使い分けましょう。
引数の挙動 — 値渡しと参照のコピー
JSは常に値渡しですが、オブジェクトの場合は参照のコピーが渡されるため、関数内でプロパティを変更すると外側に反映されます。
// プロパティ変更は外側に反映される
function modifyObject(obj) {
obj.value = 'fuga';
}
const myObject = { value: 'hoge' };
modifyObject(myObject);
console.log(myObject.value); // "fuga"
// 再代入は外側に影響しない
function reassign(obj) {
obj = { value: 'bar' };
}
const o = { value: 'hoge' };
reassign(o);
console.log(o.value); // "hoge"
// プリミティブは常に値のコピー
function modifyPrimitive(v) { v = 10; }
let x = 5;
modifyPrimitive(x);
console.log(x); // 5
クラス — class
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
const u = new User("Alice");
console.log(u.greet());
ES6 から使えるクラス構文です。constructor でインスタンス生成時の初期化を行います。
デバッグ — スタックトレース
function debugTrace() {
console.log(new Error("trace").stack);
}
Error: trace
at debugTrace (article_form.js:26:15)
at initViews (article_form.js:33:3)
at HTMLDocument.<anonymous> (article_form.js:21:3)
new Error().stack で呼び出し元をトレースできます。どこから呼ばれているか分からなくなったときに便利です。
DOM操作 — data属性へのアクセス
<div id="user" data-id="123" data-role="admin"></div>
const el = document.getElementById("user");
console.log(el.dataset.id); // "123"
console.log(el.dataset.role); // "admin"
el.dataset.role = "editor"; // 設定
delete el.dataset.id; // 削除
HTML側では data-xxx、JS側では camelCase(data-user-name → dataset.userName)でアクセスします。値は文字列なので数値・真偽値として使う場合は変換が必要です。
JSON変換 — JSON.stringify / JSON.parse
// オブジェクト → JSON文字列
const obj = { name: "Alice", age: 25 };
const json = JSON.stringify(obj);
console.log(json); // {"name":"Alice","age":25}
// JSON文字列 → オブジェクト
const parsed = JSON.parse('{"name":"Alice","age":25}');
console.log(parsed.name); // Alice
localStorage への保存や API リクエストのボディ生成など、日常的に使う組み合わせです。
コレクション — Map / Set
Map はキーと値のペアを保持します。キーにオブジェクトも使えます。
const map = new Map();
map.set("name", "Taro");
console.log(map.get("name")); // "Taro"
const obj = { id: 1 };
map.set(obj, "Hanako");
console.log(map.get(obj)); // "Hanako"
Set は重複しない値のコレクションです。配列の重複除去に便利です。
const set = new Set([1, 2, 2, 3]);
console.log(set); // Set(3) {1, 2, 3}
set.add(4);
console.log(set.has(2)); // true
メモリ管理 — WeakMap / WeakSet
WeakMap はオブジェクトをキーにしたマップで、キーとなるオブジェクトが他で参照されなくなると自動削除(GC対象)されます。キャッシュや一時データに便利ですが列挙はできません。
let obj = { name: "Taro" };
const weakMap = new WeakMap();
weakMap.set(obj, "data");
console.log(weakMap.get(obj)); // "data"
obj = null; // 参照がなくなると weakMap 内からも消える
WeakSet はオブジェクトだけを格納する Set です。要素が他で参照されなくなれば自動削除されます。
let obj = { id: 1 };
const weakSet = new WeakSet();
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null;
GC のタイミングは保証されません。
DOM監視 — MutationObserver
MutationObserver は DOM の変化を監視するブラウザAPIです。子要素の追加・削除、属性・テキストの変更などを検知してコールバックを実行します。
const callback = (mutationsList) => {
mutationsList.forEach(mutation => {
console.log(mutation.type);
});
};
const observer = new MutationObserver(callback);
const targetNode = document.getElementById("nuContents");
observer.observe(targetNode, {
childList: true, // 子要素の追加・削除
attributes: true, // 属性の変更
characterData: true, // テキスト内容の変更
subtree: true // 子孫要素も監視
});
jQuery拡張としての実装例
この仕組みを応用して、hidden input の値変化を監視する jQuery プラグインです。
注意:
MutationObserverが検知するのはsetAttribute("value", ...)のような DOM属性の変更 のみです。element.value = ...や jQuery の.val(...)はプロパティ変更なので発火しません。このプラグインはsetAttributeで値を書き込むコードと組み合わせて使う前提です。
(function($) {
$.fn.observeValue = function(callback) {
return this.each(function() {
if (this.tagName.toLowerCase() !== 'input' || this.type !== 'hidden') {
throw new Error('observeValue(): 対象は input[type="hidden"] のみです');
}
var observer = new MutationObserver(function(mutations, obs) {
callback.call(this, mutations, obs);
}.bind(this));
observer.observe(this, { attributes: true, attributeFilter: ["value"] });
});
};
})(jQuery);
// 先に observer を登録してから setAttribute で値をセットすると発火する
$("#myHidden").observeValue(function() {
console.log("hiddenの値が変更されました:", this.getAttribute("value"));
});
document.getElementById("myHidden").setAttribute("value", "new-value");
関連記事
- React + Vite の初歩的な理解を深める
- Cloudflare Worker を使うと静的サイトにサーバーレスな受付口を作れて便利
- Playwright入門。リリース前のUI確認を自動化するメリットと導入手順
