アルゴリズム概要

問題の説明

与えられた値 obj が、指定されたクラス classFunction(またはそのスーパークラス)のインスタンスであるかを判定する関数を実装します。

重要な要件

入出力例

checkIfInstanceOf(new Date(), Date)  // true
checkIfInstanceOf(5, Number)         // true (プリミティブ対応)
checkIfInstanceOf(5, String)         // false
checkIfInstanceOf(null, Object)      // false

class Animal {}
class Dog extends Animal {}
checkIfInstanceOf(new Dog(), Animal) // true (継承)

戦略

  1. 早期リターン: null/undefined や不正な classFunction を即座に除外
  2. プリミティブ処理: Object() でラッパーオブジェクト化(1回のみ)
  3. プロトタイプチェーン走査: isPrototypeOf() でV8最適化を活用
  4. 型安全性: TypeScript の型ガードで実行時安全性を確保

主要ポイント

ステップバイステップ解説

TypeScript実装

/**
 * 値が指定されたクラスまたはスーパークラスのインスタンスかチェック
 *
 * @param obj - チェック対象の値(任意の型、null/undefined含む)
 * @param classFunction - クラスコンストラクタ
 * @returns obj が classFunction(またはそのスーパークラス)のインスタンスなら true
 *
 * @complexity
 * - Time: O(d) - d はプロトタイプチェーンの深度(通常3-10)
 * - Space: O(1) - 固定サイズの変数のみ使用
 */
var checkIfInstanceOf = function(obj: unknown, classFunction: unknown): boolean {
    // 早期リターン: null/undefined または classFunction が関数でない
    if (obj == null || typeof classFunction !== 'function') {
        return false;
    }

    // プリミティブはボックス化
    // typeof による型判定(object と function 以外は全てプリミティブ)
    if (typeof obj !== 'object' && typeof obj !== 'function') {
        // Object() はプリミティブを対応するラッパーオブジェクトに変換
        // 例: Object(5) → Number {5}, Object("a") → String {"a"}
        obj = Object(obj);
    }

    // Optional Chaining + Nullish Coalescing で安全に処理
    // ?. により prototype が undefined の場合(Arrow関数等)は undefined を返す
    // ?? により undefined の場合は false を返す
    return (classFunction as any).prototype?.isPrototypeOf(obj as object) ?? false;
};

フローチャート

開始 obj が null/undefined? いいえ classFunction が 関数? はい obj が プリミティブ? はい obj を Object(obj) 化 いいえ classFunction .prototype を取得 prototype が 存在? はい isPrototypeOf で検証 結果を返す はい いいえ いいえ false 返却

フローの説明:
1. null/undefined チェック: obj が null または undefined なら即座に false
2. 関数チェック: classFunction が関数でなければ false
3. プリミティブ処理: プリミティブ値なら Object() でボックス化
4. prototype取得: classFunction.prototype を取得
5. isPrototypeOf検証: プロトタイプチェーン内に存在するか確認
6. 結果返却: true/false を返す

計算量分析

項目 計算量 説明
時間計算量 O(d) d はプロトタイプチェーンの深度(通常3-10)
isPrototypeOf() がチェーンを走査
空間計算量 O(1) プリミティブのボックス化のみ
新規オブジェクト生成は最小限

アプローチ比較

アプローチ Time Space 備考
isPrototypeOf() ✅ O(d) O(1) 推奨: V8最適化 + TypeScript型安全
__proto__ 走査 O(d) O(1) 非標準、型定義が曖昧
Object.getPrototypeOf() O(d) O(1) 手動ループ、関数呼び出しコスト
instanceof O(d) O(1) プリミティブ非対応

V8 最適化ポイント