概要:このチュートリアルでは、ES6におけるJavaScriptのリフレクションとReflect APIについて学びます。
リフレクションとは
コンピュータプログラミングにおいて、リフレクションとは、プログラムが実行時にオブジェクトの変数、プロパティ、およびメソッドを操作する機能です。
ES6以前でも、JavaScriptにはリフレクション機能が既に存在していましたが、コミュニティや仕様書では正式にそう呼ばれていませんでした。たとえば、`Object.keys()`、`Object.getOwnPropertyDescriptor()`、`Array.isArray()`などのメソッドは、従来のリフレクション機能です。
ES6では、メソッドの呼び出し、オブジェクトの構築、プロパティの取得と設定、プロパティの操作と拡張を可能にする`Reflect`という新しいグローバルオブジェクトが導入されました。
`Reflect` APIは、動的コードを処理できるプログラムやフレームワークの開発を可能にするため、重要です。
Reflect API
ほとんどのグローバルオブジェクトとは異なり、`Reflect`はコンストラクタではありません。つまり、`new`演算子で`Reflect`を使用したり、`Reflect`を関数として呼び出したりすることはできません。 `Math`オブジェクトや`JSON`オブジェクトと似ています。 `Reflect`オブジェクトのすべてのメソッドは静的です。
- `Reflect.apply()` – 指定された引数で関数を呼び出します。
- `Reflect.construct()` – `new`演算子のように動作しますが、関数として動作します。 `new target(...args)`を呼び出すことと同じです。
- `Reflect.defineProperty()` – `Object.defineProperty()`に似ていますが、プロパティがオブジェクトに正常に定義されたかどうかを示すブール値を返します。
- `Reflect.deleteProperty()` – `delete`演算子のように動作しますが、関数として動作します。 `delete objectName[propertyName]`を呼び出すことと同じです。
- `Reflect.get()` – プロパティの値を返します。
- `Reflect.getOwnPropertyDescriptor()` – `Object.getOwnPropertyDescriptor()`に似ています。オブジェクトにプロパティが存在する場合は、そのプロパティのプロパティ記述子を返し、そうでない場合は`undefined`を返します。
- `Reflect.getPrototypeOf()` – `Object.getPrototypeOf()`と同じです。
- `Reflect.has()` – `in`演算子のように動作しますが、関数として動作します。プロパティ(所有または継承)が存在するかどうかを示すブール値を返します。
`Reflect.isExtensible()` – `Object.isExtensible()`と同じです。 - `Reflect.ownKeys()` – オブジェクトの所有プロパティキー(継承されていない)の配列を返します。
- `Reflect.preventExtensions()` – `Object.preventExtensions()`に似ています。ブール値を返します。
- `Reflect.set()` – プロパティに値を代入し、プロパティが正常に設定された場合はtrueとなるブール値を返します。
- `Reflect.setPrototypeOf()` – オブジェクトのプロトタイプを設定します。
Reflect APIの使用例をいくつか見てみましょう。
オブジェクトの作成:Reflect.construct()
`Reflect.construct()`メソッドは、`new`演算子のように動作しますが、関数として動作します。異なるプロトタイプを指定できることを除けば、`new target(...args)`を呼び出すことと同じです。
Reflect.construct(target, args [, newTarget])
Code language: CSS (css)
`Reflect.construct()`は、`target`の新しいインスタンス、または指定された場合は`newTarget`を返します。これは、`target`によってコンストラクタとして初期化され、指定された配列のようなオブジェクト`args`が使用されます。次の例を参照してください。
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
};
let args = ['John', 'Doe'];
let john = Reflect.construct(
Person,
args
);
console.log(john instanceof Person);
console.log(john.fullName); // John Doe
Code language: JavaScript (javascript)
出力
true
John Doe
Code language: JavaScript (javascript)
この例では
- まず、`Person`というクラスを定義します。
- 次に、2つの文字列を含む`args`配列を宣言します。
- 3番目に、`Reflect.construct()`メソッドを使用して`Person`クラスの新しいインスタンスを作成します。 `john`オブジェクトは`Person`クラスのインスタンスであるため、`fullName`プロパティを持っています。
関数の呼び出し:Reflect.apply()
ES6以前は、`Function.prototype.apply()`メソッドを使用して、指定された`this`値と`arguments`で関数を呼び出していました。例えば
let result = Function.prototype.apply.call(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)
出力
30
この構文はかなり冗長です。
`Reflect.apply()`は、`Function.prototype.apply()`と同じ機能を提供しますが、冗長性が少なく、理解しやすいです。
let result = Reflect.apply(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)
`Reflect.apply()`メソッドの構文は次のとおりです。
Reflect.apply(target, thisArg, args)
Code language: JavaScript (javascript)
プロパティの定義:Reflect.defineProperty()
`Reflect.defineProperty()`は`Object.defineProperty()`に似ています。ただし、例外をスローする代わりに、プロパティが正常に定義されたかどうかを示すブール値を返します。
Reflect.defineProperty(target, propertyName, propertyDescriptor)
Code language: JavaScript (javascript)
次の例を参照してください。
let person = {
name: 'John Doe'
};
if (Reflect.defineProperty(person, 'age', {
writable: true,
configurable: true,
enumerable: false,
value: 25,
})) {
console.log(person.age);
} else {
console.log('Cannot define the age property on the person object.');
}
Code language: JavaScript (javascript)
このチュートリアルでは、JavaScriptのリフレクションと、多数のリフレクションメソッドを含むReflect APIについて学びました。