トップレベルawaitの非同期処理最適化
非同期初期化の簡素化
従来のコールバック地獄を解消する非同期処理の新アプローチ:
// 複雑なネスト構造
初期化処理(設定 => {
データ取得(設定.id, 結果 => {
レンダリング(設定, 結果);
});
});
async/awaitによる線形化処理:
const プロファイル読み込み = async () => {
const 設定 = await 初期化処理();
const 結果 = await データ取得(設定.id);
レンダリング(設定, 結果);
};
モジュール初期化の具体例
// 設定モジュールの非同期初期化
export const 環境設定 = await fetch('/config')
.then(res => res.json())
.catch(() => デフォルト設定());
// 他モジュールでの直接利用
import { 環境設定 } from './env.js';
console.log(環境設定.apiEndpoint);
// ブラウザ機能検出に基づくダイナミックインポート
const 旧式対応必要 = await ブラウザ検証();
if (旧式対応必要) {
await import('./polyfill-loader.js');
}
Object.hasOwnによる安全なプロパティ検証
プロパティ検査手法の比較
class 輸送手段 {
constructor(モデル) {
this.model = モデル;
}
}
class 自動車 extends 輸送手段 {
constructor(モデル, 排気量) {
super(モデル);
this.engine = 排気量;
}
}
自動車.prototype.種別 = '乗用車';
const myCar = new 自動車('Camry', '2.5L');
// 1. in演算子(プロトタイプチェーンを検索)
console.log('model' in myCar); // true
console.log('種別' in myCar); // true
// 2. Object.hasOwn(自身のプロパティのみ検証)
console.log(Object.hasOwn(myCar, 'model')); // true
console.log(Object.hasOwn(myCar, '種別')); // false
特殊ケースへの対応
// プロトタイプなしオブジェクトの処理
const 無プロトオブジェクト = Object.create(null);
無プロトオブジェクト.値 = 'データ';
// 旧メソッドではエラー
console.log(Object.hasOwn(無プロトオブジェクト, '値')); // true
// 悪意のあるhasOwnPropertyオーバーライド
const 悪意あるオブジェクト = {
データ: '重要情報',
hasOwnProperty: () => true
};
console.log(Object.hasOwn(悪意あるオブジェクト, 'データ')); // true
配列.at()メソッドによる直感的インデックス操作
従来のインデックス操作の課題
const 時間帯 = ['UTC', 'JST', 'EST', 'PST', 'CET'];
// 末尾要素取得の複雑さ
const 最終要素 = 時間帯[時間帯.length - 1];
// 負のインデックスの手動計算
function 取得(配列, 位置) {
return 位置 < 0 ? 配列[配列.length + 位置] : 配列[位置];
}
.at()メソッドの実用例
const 通貨 = ['USD', 'EUR', 'JPY', 'GBP', 'CNY'];
// 負のインデックスによる末尾からの参照
console.log(通貨.at(-1)); // 'CNY'
console.log(通貨.at(-3)); // 'JPY'
// セーフティな境界値処理
console.log(通貨.at(100)); // undefined
console.log(通貨.at(-100)); // undefined
// 時間周期ユーティリティの実装
class 時間サイクル {
constructor(要素) {
this.elements = 要素;
}
取得(インデックス) {
return this.elements.at(インデックス % this.elements.length);
}
}
const 曜日 = new 時間サイクル(['月', '火', '水', '木', '金']);
console.log(曜日.取得(7)); // '火'
console.log(曜日.取得(-1)); // '金'
Error Causeによるエラー連鎖管理
エラー原因の追跡実装
class システムエラー extends Error {
constructor(メッセージ, { 原因, コード } = {}) {
super(メッセージ);
this.name = 'システムエラー';
this.cause = 原因;
this.code = コード;
}
}
async function 支払い処理(金額) {
try {
await 与信確認(金額);
return await 決済実行(金額);
} catch (エラー) {
throw new システムエラー(
`支払い処理失敗: ${金額}円`,
{ 原因: エラー, コード: 'PAYMENT_FAILED' }
);
}
}
// エラー連鎖の確認
try {
await 支払い処理(5000);
} catch (エラー) {
console.error('主要エラー:', エラー.message);
console.error('根本原因:', エラー.cause.message);
}
プライベートフィールドによる真のカプセル化
クラスの実装例
class 図書管理システム {
#蔵書 = new Map();
#貸出履歴 = new Map();
#稼働状態 = false;
constructor() {
this.#初期化();
}
async #初期化() {
const 本データ = await this.#データ取得();
本データ.forEach(本 => {
this.#蔵書.set(本.id, 本);
});
this.#稼働状態 = true;
}
#ログ記録(操作, 書籍ID) {
const 履歴 = this.#貸出履歴.get(書籍ID) || [];
履歴.push({ 操作, 時刻: new Date() });
this.#貸出履歴.set(書籍ID, 履歴);
}
貸出(書籍ID) {
if (!this.#稼働状態) throw new Error('システム未起動');
if (!this.#蔵書.has(書籍ID)) throw new Error('書籍不存在');
this.#ログ記録('貸出', 書籍ID);
return this.#蔵書.get(書籍ID);
}
// プライベートプロパティへの直接アクセス不可
// this.#蔵書 = new Map(); // エラー
}