JavaScript/Number/prototype/constructor

カテゴリ:Book:JavaScript#Number/prototype/constructor%20

Number.prototype.constructor は、ECMAScript における Number オブジェクトのプロトタイププロパティで、Number オブジェクトのインスタンスを生成した関数を参照します。デフォルトでは、Number.prototype.constructor プロパティは Number コンストラクタ自体を指します[1]

構文

Number.prototype.constructor

特性

Number.prototype.constructor には、以下のような特性があります:

  • プロトタイププロパティ: このプロパティは Number.prototype オブジェクトに属し、すべての Number インスタンスから継承されます。
  • 参照のみ: constructor プロパティは通常、参照するためだけに使用され、直接呼び出すことは少ないです。
  • 変更可能: constructor プロパティは書き換え可能ですが、通常は変更しないことが推奨されます。
  • ECMAScript 1: このプロパティは ECMAScript 1 から存在しています。

基本的な使用法

以下のプログラムは、Number.prototype.constructor の基本的な使用法を示しています。

// Number インスタンスの constructor プロパティへのアクセス
const num = new Number(42);
console.log(num.constructor === Number); // true

// Number.prototype.constructor への直接アクセス
console.log(Number.prototype.constructor === Number); // true

// constructor を使用して新しい Number インスタンスを作成
const num1 = new Number(123);
const num2 = new num1.constructor(456);
console.log(num2); // Number {456}
console.log(typeof num2); // object
console.log(num2 instanceof Number); // true

このプログラムでは、Number.prototype.constructorNumber コンストラクタを参照していることを確認し、その constructor プロパティを使用して新しい Number インスタンスを作成する例を示しています。

型の識別

以下のプログラムは、Number.prototype.constructor を使用してオブジェクトの型を識別する例を示しています。

// constructor プロパティを使用した型の識別
function identifyType(value) {
  // プリミティブ値の場合はオブジェクトラッパーを作成
  const obj = Object(value);
  
  // constructor プロパティを取得
  const constructor = obj.constructor;
  
  // constructor の名前を返す
  return constructor.name;
}

// 様々な値の型を識別
console.log(identifyType(42)); // 'Number'
console.log(identifyType(3.14)); // 'Number'
console.log(identifyType(new Number(100))); // 'Number'
console.log(identifyType('hello')); // 'String'
console.log(identifyType(true)); // 'Boolean'
console.log(identifyType({})); // 'Object'
console.log(identifyType([])); // 'Array'
console.log(identifyType(new Date())); // 'Date'
console.log(identifyType(/regex/)); // 'RegExp'
console.log(identifyType(function() {})); // 'Function'

このプログラムでは、Number.prototype.constructor を含むオブジェクトの constructor プロパティを使用して、変数の型を識別する関数の例を示しています。プリミティブ値に対しては、まず Object() コンストラクタでラップしてからコンストラクタにアクセスしています。

プロトタイプの継承

以下のプログラムは、Number.prototype.constructor とプロトタイプ継承の関係を示しています。

// カスタムの Number 拡張クラス
class MyNumber extends Number {
  isPositive() {
    return this > 0;
  }
  
  isNegative() {
    return this < 0;
  }
  
  isZero() {
    return this == 0;
  }
}

// MyNumber インスタンスの作成
const myNum = new MyNumber(42);
console.log(myNum.valueOf()); // 42
console.log(myNum.isPositive()); // true

// constructor の確認
console.log(myNum.constructor === MyNumber); // true
console.log(myNum.constructor === Number); // false

// プロトタイプチェーンの確認
console.log(myNum instanceof MyNumber); // true
console.log(myNum instanceof Number); // true

// constructor を使用して新しいインスタンスを作成
const myNum2 = new myNum.constructor(-10);
console.log(myNum2.valueOf()); // -10
console.log(myNum2.isNegative()); // true

このプログラムでは、Number クラスを拡張したカスタムクラスを作成し、そのインスタンスの constructor プロパティを確認しています。MyNumber クラスのインスタンスの constructor プロパティは MyNumber コンストラクタを参照し、このプロパティを使用して新しいインスタンスを作成できることを示しています。

実用的な例

オブジェクトの複製

以下のプログラムは、Number.prototype.constructor を使用してオブジェクトを複製する例を示しています。

// オブジェクトのコンストラクタを使用して複製を作成する関数
function cloneUsingConstructor(obj) {
  // null または undefined の場合
  if (obj === null || obj === undefined) {
    return obj;
  }
  
  // プリミティブ値の場合はそのまま返す
  if (typeof obj !== 'object' && typeof obj !== 'function') {
    return obj;
  }
  
  try {
    // 元のオブジェクトと同じコンストラクタを使用して新しいインスタンスを作成
    const clone = new obj.constructor();
    
    // プロパティをコピー
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        clone[key] = obj[key];
      }
    }
    
    return clone;
  } catch (e) {
    // コンストラクタが使用できない場合は通常のオブジェクトを返す
    console.warn('コンストラクタを使用した複製に失敗しました:', e);
    return Object.assign({}, obj);
  }
}

// 使用例
const numObj = new Number(100);
numObj.custom = 'テスト';

const numClone = cloneUsingConstructor(numObj);
console.log(numClone instanceof Number); // true
console.log(numClone.valueOf()); // 100
console.log(numClone.custom); // 'テスト'

// 他の型のオブジェクトでも機能する
const dateObj = new Date();
const dateClone = cloneUsingConstructor(dateObj);
console.log(dateClone instanceof Date); // true
console.log(dateClone.getTime() === dateObj.getTime()); // true

// プリミティブ値の場合
console.log(cloneUsingConstructor(42)); // 42
console.log(cloneUsingConstructor('hello')); // 'hello'

このプログラムでは、オブジェクトの constructor プロパティを使用して、同じ型の新しいインスタンスを作成し、元のオブジェクトのプロパティをコピーする関数の例を示しています。これにより、Number オブジェクトを含む様々な型のオブジェクトを適切に複製できます。

動的なオブジェクト生成

以下のプログラムは、型名から動的に新しいオブジェクトを生成する例を示しています。

// グローバルコンストラクタのマッピング
const constructors = {
  'Number': Number,
  'String': String,
  'Boolean': Boolean,
  'Array': Array,
  'Object': Object,
  'Date': Date,
  'RegExp': RegExp
};

// 型名と引数からオブジェクトを動的に生成する関数
function createObjectOfType(typeName, ...args) {
  // 指定された型名に対応するコンストラクタを取得
  const Constructor = constructors[typeName];
  
  if (!Constructor) {
    throw new Error(`未知の型名です: ${typeName}`);
  }
  
  // コンストラクタを使用して新しいインスタンスを作成
  return new Constructor(...args);
}

// 使用例
const dynamicNumber = createObjectOfType('Number', 42);
console.log(dynamicNumber instanceof Number); // true
console.log(dynamicNumber.valueOf()); // 42

const dynamicDate = createObjectOfType('Date', 2023, 0, 1); // 2023年1月1日
console.log(dynamicDate instanceof Date); // true
console.log(dynamicDate.getFullYear()); // 2023

// テキストデータから動的にオブジェクトを生成
function parseDataToObject(data) {
  const [typeName, ...values] = data.split(':');
  const parsedValues = values.map(val => {
    // 数値に変換可能な場合は変換
    const numVal = Number(val);
    return isNaN(numVal) ? val : numVal;
  });
  
  return createObjectOfType(typeName, ...parsedValues);
}

// データ文字列からオブジェクトを生成
console.log(parseDataToObject('Number:123').valueOf()); // 123
console.log(parseDataToObject('String:Hello,World').valueOf()); // 'Hello,World'
console.log(parseDataToObject('Date:2023,5,15').toLocaleDateString()); // '2023/6/15' (月は0から始まるため)

このプログラムでは、型名を指定して動的にオブジェクトを生成する関数の例を示しています。constructor プロパティと同様に、コンストラクタ関数を使用して新しいインスタンスを作成しています。また、テキストデータから型情報を解析し、適切な型のオブジェクトを生成する例も含まれています。

フォームデータのバリデーション

以下のプログラムは、Number.prototype.constructor を使用してフォームデータのバリデーションを行う例を示しています。

// フォームフィールドのバリデーションクラス
class FormValidator {
  constructor() {
    this.validationRules = {
      number: {
        constructor: Number,
        validate: (value) => !isNaN(Number(value)),
        message: '数値を入力してください'
      },
      string: {
        constructor: String,
        validate: (value) => typeof value === 'string' && value.trim() !== '',
        message: '文字列を入力してください'
      },
      boolean: {
        constructor: Boolean,
        validate: (value) => typeof value === 'boolean' || value === 'true' || value === 'false',
        message: '真偽値を入力してください'
      },
      date: {
        constructor: Date,
        validate: (value) => {
          const date = new Date(value);
          return !isNaN(date.getTime());
        },
        message: '有効な日付を入力してください'
      }
    };
  }
  
  // フィールドを検証してキャストする
  validateAndCast(fieldName, value, type) {
    const rule = this.validationRules[type];
    
    if (!rule) {
      throw new Error(`未知の型です: ${type}`);
    }
    
    // バリデーション
    if (!rule.validate(value)) {
      return {
        valid: false,
        fieldName,
        message: rule.message
      };
    }
    
    // 適切な型に変換
    let castedValue;
    
    if (type === 'boolean') {
      // 文字列 'true'/'false' を適切にキャスト
      castedValue = value === true || value === 'true';
    } else if (type === 'number') {
      // 文字列を数値に変換
      castedValue = new rule.constructor(value).valueOf();
    } else if (type === 'date') {
      // 文字列を Date に変換
      castedValue = new rule.constructor(value);
    } else {
      // その他の型
      castedValue = new rule.constructor(value);
    }
    
    return {
      valid: true,
      fieldName,
      value: castedValue
    };
  }
  
  // フォームデータを検証して処理
  validateForm(formData) {
    const results = {
      valid: true,
      fields: {},
      errors: []
    };
    
    for (const field of formData) {
      const { name, value, type } = field;
      
      const validationResult = this.validateAndCast(name, value, type);
      
      if (validationResult.valid) {
        results.fields[name] = validationResult.value;
      } else {
        results.valid = false;
        results.errors.push({
          field: name,
          message: validationResult.message
        });
      }
    }
    
    return results;
  }
}

// 使用例
const validator = new FormValidator();

// フォームデータの例
const formData = [
  { name: 'age', value: '25', type: 'number' },
  { name: 'name', value: 'John', type: 'string' },
  { name: 'isActive', value: 'true', type: 'boolean' },
  { name: 'birthdate', value: '1998-05-12', type: 'date' },
  { name: 'invalidNumber', value: 'abc', type: 'number' }
];

const validationResults = validator.validateForm(formData);
console.log('フォームは有効か:', validationResults.valid); // false
console.log('検証済みフィールド:', validationResults.fields);
/*
{
  age: 25,
  name: 'John',
  isActive: true,
  birthdate: 1998-05-12T00:00:00.000Z
}
*/
console.log('エラー:', validationResults.errors);
/*
[
  {
    field: 'invalidNumber',
    message: '数値を入力してください'
  }
]
*/

このプログラムでは、各型のコンストラクタを使用してフォームデータを検証し、適切な JavaScript の型に変換する例を示しています。コンストラクタを利用することで、型に応じた適切な変換とバリデーションを行っています。

Number.prototype.constructor と他の Number プロパティの比較

Number オブジェクトには、Number.prototype.constructor 以外にも様々なプロパティとメソッドがあります。以下はその比較です:

// Number オブジェクトのプロパティとメソッドの比較
const num = new Number(123.456);

// プロトタイププロパティの確認
console.log('Number.prototype.constructor:', num.constructor === Number); // true

// インスタンスメソッド
console.log('toString():', num.toString()); // '123.456'
console.log('toString(16):', num.toString(16)); // '7b.74bc6a7ef9db' (16進数)
console.log('valueOf():', num.valueOf()); // 123.456
console.log('toFixed(2):', num.toFixed(2)); // '123.46'
console.log('toExponential(2):', num.toExponential(2)); // '1.23e+2'
console.log('toLocaleString():', num.toLocaleString()); // '123.456' (ロケールに依存)

// 静的メソッドとの比較
console.log('Number.parseFloat("123.456"):', Number.parseFloat('123.456')); // 123.456
console.log('Number.parseInt("123.456", 10):', Number.parseInt('123.456', 10)); // 123

// constructor は直接呼び出し可能
const newNum = new num.constructor(789);
console.log('new num.constructor(789):', newNum.valueOf()); // 789

このプログラムでは、Number.prototype.constructor と他の Number オブジェクトのプロパティおよびメソッドを比較しています。constructor はプロトタイププロパティであり、Number コンストラクタ自体を参照します。一方、Number.prototype のメソッドは数値の操作や変換を行い、静的メソッドは型変換機能を提供します。

その他の JavaScript オブジェクトの constructor プロパティ

JavaScript では、すべてのオブジェクトが constructor プロパティを持っています。以下は他の組み込みオブジェクトの constructor プロパティの例です:

// 様々な JavaScript オブジェクトの constructor プロパティ
const examples = [
  { type: 'Number', value: new Number(42) },
  { type: 'String', value: new String('hello') },
  { type: 'Boolean', value: new Boolean(true) },
  { type: 'Array', value: new Array(1, 2, 3) },
  { type: 'Object', value: new Object({ a: 1 }) },
  { type: 'Date', value: new Date() },
  { type: 'RegExp', value: new RegExp('\\d+') },
  { type: 'Function', value: new Function('return 42') }
];

console.log('様々な JavaScript オブジェクトの constructor プロパティ:');
examples.forEach(({ type, value }) => {
  console.log(`${type}.prototype.constructor === ${type}:`, value.constructor === globalThis[type]);

  // constructor を使って新しいインスタンスを作成
  const newInstance = new value.constructor();
  console.log(`new ${type} instance:`, newInstance);
  console.log(`instance of ${type}:`, newInstance instanceof globalThis[type]);
  console.log('---');
});

このプログラムでは、様々な JavaScript 組み込みオブジェクトの constructor プロパティを確認し、それらを使用して新しいインスタンスを作成しています。すべての組み込みオブジェクトの constructor プロパティは、そのオブジェクトタイプのコンストラクタ関数を参照しています。

脚註

  1. Number.prototype.constructor は、すべての JavaScript オブジェクトのプロトタイプに存在するプロパティの一つです。

外部リンク

カテゴリ:Book:JavaScript#Number/prototype/constructor%20 カテゴリ:JavaScript
カテゴリ:Book:JavaScript カテゴリ:JavaScript カテゴリ:Pages using the JsonConfig extension