反映する
概要
Reflect
オブジェクトは、Proxy
オブジェクトと同様に、オブジェクトを操作するために ES6 によって提供される新しい API です。 「Reflect」オブジェクトは、いくつかの目的のために設計されています。
(1) 明らかに言語の内部にある Object
オブジェクトのいくつかのメソッド (Object.defineProperty
など) を Reflect
オブジェクトに配置します。この段階では、一部のメソッドは Object
と Reflect
オブジェクトの両方にデプロイされており、将来の新しいメソッドは Reflect
オブジェクトにのみデプロイされます。言い換えれば、言語の内部メソッドは Reflect
オブジェクトから取得できます。
(2) いくつかの Object
メソッドの戻り結果を変更して、より合理的なものにします。たとえば、Object.defineProperty(obj, name, desc)
はプロパティを定義できない場合にエラーをスローしますが、Reflect.defineProperty(obj, name, desc)
は false
を返します。
//古い書き方
試す {
Object.defineProperty(ターゲット、プロパティ、属性);
//成功
} キャッチ (e) {
// 失敗
}
//新しい書き方
if (Reflect.defineProperty(ターゲット, プロパティ, 属性)) {
//成功
} それ以外 {
// 失敗
}
(3) 「オブジェクト」の操作を関数的な動作にします。 「name in obj」や「delete obj[name]」など、一部の「Object」操作は必須ですが、「Reflect.has(obj, name)」や「Reflect.deleteProperty(obj, name)」によって機能するようになりました。行動。
//古い書き方
'assign' in Object // true
//新しい書き方
Reflect.has(Object, 'assign') // true
(4) Reflect オブジェクトのメソッドと Proxy オブジェクトのメソッドは 1 対 1 に対応します。 Proxy オブジェクトのメソッドであれば、対応するメソッドが 上に見つかります。 Reflect
オブジェクト。これにより、「Proxy」オブジェクトは、対応する「Reflect」メソッドを簡単に呼び出してデフォルトの動作を完了し、動作を変更するための基礎として機能することができます。言い換えれば、「Proxy」がデフォルトの動作をどのように変更しても、「Reflect」では常にデフォルトの動作を取得できます。
プロキシ(ターゲット, {
set: function(ターゲット、名前、値、受信者) {
var success = Reflect.set(ターゲット、名前、値、受信者);
if (成功) {
console.log('プロパティ ' + 名前 + ' 上の ' + ターゲット + ' に設定 + 値);
}
成功を返します。
}
});
上記のコードでは、「Proxy」メソッドが「target」オブジェクトの属性割り当て動作をインターセプトします。 Reflect.set
メソッドを使用してオブジェクトのプロパティに値を割り当て、元の動作が完了していることを確認してから、追加の機能をデプロイします。
別の例を示します。
var loggedObj = 新しいプロキシ(obj, {
get(ターゲット, 名前) {
console.log('get', ターゲット, 名前);
return Reflect.get(ターゲット, 名前);
}、
deleteProperty(ターゲット, 名前) {
console.log('削除' + 名前);
return Reflect.deleteProperty(ターゲット, 名前);
}、
has(ターゲット, 名前) {
console.log('が' + 名前);
return Reflect.has(ターゲット, 名前);
}
});
上記のコードでは、「Proxy」オブジェクトの各インターセプト操作 (「get」、「delete」、「has」) は、対応する「Reflect」メソッドを内部で呼び出して、ネイティブの動作が正常に実行できることを確認します。追加された作業は、操作ごとに 1 行のログを出力することです。
「Reflect」オブジェクトを使用すると、多くの操作が読みやすくなります。
//古い書き方
Function.prototype.apply.call(Math.floor, 未定義, [1.75]) // 1
//新しい書き方
Reflect.apply(Math.floor, 未定義, [1.75]) // 1
静的メソッド
「Reflect」オブジェクトには合計 13 個の静的メソッドがあります。
- Reflect.apply(target, thisArg, args)
- Reflect.construct(ターゲット, 引数)
- Reflect.get(ターゲット、名前、受信者)
- Reflect.set(ターゲット、名前、値、受信者)
- Reflect.defineProperty(ターゲット、名前、説明)
- Reflect.deleteProperty(ターゲット, 名前)
- Reflect.has(ターゲット, 名前)
- Reflect.ownKeys(ターゲット)
- Reflect.isExtensible(ターゲット)
- Reflect.preventExtensions(ターゲット)
- Reflect.getOwnPropertyDescriptor(ターゲット, 名前)
- Reflect.getPrototypeOf(ターゲット)
- Reflect.setPrototypeOf(ターゲット, プロトタイプ)
上記のメソッドの機能のほとんどは、Object
オブジェクト上の同名のメソッドと同じであり、Proxy
オブジェクトのメソッドと 1 対 1 に対応します。以下にそれらについて説明します。
Reflect.get(ターゲット、名前、受信者)
Reflect.get
メソッドは、target
オブジェクトの name
プロパティを検索して返します。そのようなプロパティが存在しない場合は unknown
を返します。
var myObject = {
フー: 1、
バー: 2、
get baz() {
this.foo + this.bar を返します。
}、
}
Reflect.get(myObject, 'foo') // 1
Reflect.get(myObject, 'bar') // 2
Reflect.get(myObject, 'baz') // 3
name
属性が読み取り関数 (ゲッター) を展開する場合、読み取り関数の this
は receiver
にバインドされます。
var myObject = {
フー: 1、
バー: 2、
get baz() {
this.foo + this.bar を返します。
}、
};
var myReceiverObject = {
フー: 4、
バー: 4、
};
Reflect.get(myObject, 'baz', myReceiverObject) // 8
最初のパラメータがオブジェクトでない場合、「Reflect.get」メソッドはエラーを報告します。
Reflect.get(1, 'foo') // エラーを報告する
Reflect.get(false, 'foo') // エラーを報告する
Reflect.set(ターゲット、名前、値、受信者)
Reflect.set
メソッドは、target
オブジェクトの name
プロパティを value
に設定します。
var myObject = {
フー: 1、
セットバー(値) {
this.foo = 値を返します。
}、
}
myObject.foo // 1
Reflect.set(myObject, 'foo', 2);
myObject.foo // 2
Reflect.set(myObject, 'bar', 3)
myObject.foo // 3
name
属性が代入関数を設定する場合、代入関数の this
は receiver
にバインドされます。
var myObject = {
フー: 4、
セットバー(値) {
this.foo = 値を返します。
}、
};
var myReceiverObject = {
フー: 0、
};
Reflect.set(myObject, 'bar', 1, myReceiverObject);
myObject.foo // 4
myReceiverObject.foo // 1
Proxy
オブジェクトと Reflect
オブジェクトが一緒に使用される場合、前者は代入操作をインターセプトし、後者は代入のデフォルト動作を完了し、receiver
が渡されてから Reflect.set
が渡されることに注意してください。 Proxy.defineProperty
インターセプトをトリガーします。
p = { とします
a:「あ」
};
let ハンドラー = {
set(ターゲット、キー、値、受信者) {
console.log('セット');
Reflect.set(ターゲット、キー、値、レシーバー)
}、
defineProperty(ターゲット、キー、属性) {
console.log('定義プロパティ');
Reflect.defineProperty(ターゲット、キー、属性);
}
};
let obj = 新しいプロキシ(p, ハンドラー);
obj.a = 'A';
// セット
//プロパティを定義する
上記のコードでは、「Proxy.set」インターセプトで「Reflect.set」が使用され、「receiver」が渡されて、「Proxy.defineProperty」インターセプトがトリガーされます。これは、Proxy.set
の receiver
パラメータが常に現在の Proxy
インスタンス (つまり、上記の例では obj
) を指しており、Reflect.set
が receiver
に渡されると、属性には receiver
(つまり obj
) が割り当てられ、defineProperty
インターセプトがトリガーされます。 Reflect.set
が receiver
に渡されない場合、defineProperty
インターセプトはトリガーされません。
p = { とします
a:「あ」
};
let ハンドラー = {
set(ターゲット、キー、値、受信者) {
console.log('セット');
Reflect.set(ターゲット、キー、値)
}、
defineProperty(ターゲット、キー、属性) {
console.log('定義プロパティ');
Reflect.defineProperty(ターゲット、キー、属性);
}
};
let obj = 新しいプロキシ(p, ハンドラー);
obj.a = 'A';
//セット
最初のパラメータがオブジェクトでない場合、Reflect.set
はエラーを報告します。
Reflect.set(1, 'foo', {}) // エラーを報告する
Reflect.set(false, 'foo', {}) // エラーを報告する
Reflect.has(obj, 名前)
Reflect.has
メソッドは、name in obj
の in
演算子に対応します。
var myObject = {
フー: 1、
};
//古い書き方
myObject の 'foo' // true
//新しい書き方
Reflect.has(myObject, 'foo') // true
Reflect.has()
メソッドの最初のパラメータがオブジェクトでない場合、エラーが報告されます。
Reflect.deleteProperty(obj, 名前)
Reflect.deleteProperty
メソッドは delete obj[name]
と同等であり、オブジェクトのプロパティを削除するために使用されます。
const myObj = { foo: 'bar' };
//古い書き方
myObj.fooを削除します。
//新しい書き方
Reflect.deleteProperty(myObj, 'foo');
このメソッドはブール値を返します。削除が成功した場合、または削除された属性が存在しない場合は、「true」を返します。削除が失敗し、削除された属性がまだ存在する場合は、「false」を返します。
Reflect.deleteProperty()
メソッドの最初のパラメータがオブジェクトでない場合、エラーが報告されます。
Reflect.construct(ターゲット, 引数)
Reflect.construct
メソッドは new target(...args)
と同等であり、new
を使用せずにコンストラクターを呼び出す方法を提供します。
関数 挨拶(名前) {
this.name = 名前;
}
// 新規の書き方
const インスタンス = new Greeting('張三');
// Reflect.constructの書き方
const インスタンス = Reflect.construct(挨拶, ['張三']);
Reflect.construct()
メソッドの最初のパラメータが関数でない場合、エラーが報告されます。
Reflect.getPrototypeOf(obj)
Reflect.getPrototypeOf
メソッドは、Object.getPrototypeOf(obj)
に対応するオブジェクトの __proto__
属性を読み取るために使用されます。
const myObj = 新しい FancyThing();
//古い書き方
Object.getPrototypeOf(myObj) === FancyThing.prototype;
//新しい書き方
Reflect.getPrototypeOf(myObj) === FancyThing.prototype;
「Reflect.getPrototypeOf」と「Object.getPrototypeOf」の違いの 1 つは、パラメータがオブジェクトでない場合、「Object.getPrototypeOf」はパラメータをオブジェクトに変換して実行するのに対し、「Reflect.getPrototypeOf」はエラー。
Object.getPrototypeOf(1) // 数値 {[[PrimitiveValue]]: 0}
Reflect.getPrototypeOf(1) // エラーレポート
Reflect.setPrototypeOf(obj, newProto)
Reflect.setPrototypeOf
メソッドは、Object.setPrototypeOf(obj, newProto)
メソッドに対応する、ターゲット オブジェクトのプロトタイプを設定するために使用されます。設定が成功したかどうかを示すブール値を返します。
const myObj = {};
//古い書き方
Object.setPrototypeOf(myObj, Array.prototype);
//新しい書き方
Reflect.setPrototypeOf(myObj, Array.prototype);
myObj.長さ // 0
対象オブジェクトのプロトタイプを設定できない場合(対象オブジェクトが拡張を禁止している場合など)、Reflect.setPrototypeOf
メソッドはfalse
を返します。
Reflect.setPrototypeOf({}, null)
// 真実
Reflect.setPrototypeOf(Object.freeze({}), null)
// 間違い
最初のパラメータがオブジェクトでない場合、Object.setPrototypeOf
は最初のパラメータそのものを返し、Reflect.setPrototypeOf
はエラーを報告します。
Object.setPrototypeOf(1, {})
// 1
Reflect.setPrototypeOf(1, {})
// TypeError: 非オブジェクトで呼び出された Reflect.setPrototypeOf
最初のパラメータが「unknown」または「null」の場合、「Object.setPrototypeOf」と「Reflect.setPrototypeOf」の両方がエラーを報告します。
Object.setPrototypeOf(null, {})
// TypeError: null または未定義で呼び出された Object.setPrototypeOf
Reflect.setPrototypeOf(null, {})
// TypeError: 非オブジェクトで呼び出された Reflect.setPrototypeOf
Reflect.apply(func, thisArg, args)
Reflect.apply
メソッドは、Function.prototype.apply.call(func, thisArg, args)
と同等であり、this
オブジェクトをバインドした後に指定された関数を実行するために使用されます。
一般的に、関数の this
オブジェクトをバインドしたい場合は、次のように fn.apply(obj, args)
を記述できますが、関数が独自の apply
メソッドを定義している場合は、それを記述することしかできません。 Function.prototype .apply.call(fn, obj, args) のように、Reflect オブジェクトを使用すると、この操作を簡素化できます。
定数 = [11, 33, 12, 54, 18, 96];
//古い書き方
const youngest = Math.min.apply(Math, 年齢);
const 最も古い = Math.max.apply(Math, 年齢);
const type = Object.prototype.toString.call(末っ子);
//新しい書き方
const youngest = Reflect.apply(Math.min, Math, 年齢);
const 最も古い = Reflect.apply(Math.max, Math, 年齢);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
Reflect.defineProperty(ターゲット、プロパティキー、属性)
Reflect.defineProperty
メソッドは基本的に Object.defineProperty
と同等であり、オブジェクトのプロパティを定義するために使用されます。将来的には、後者は徐々に非推奨になる予定です。今後は代わりに Reflect.defineProperty
を使用してください。
関数 MyDate() {
/*…*/
}
//古い書き方
Object.defineProperty(MyDate, 'now', {
値: () => Date.now()
});
//新しい書き方
Reflect.defineProperty(MyDate, 'now', {
値: () => Date.now()
});
Reflect.defineProperty
の最初のパラメータがオブジェクトでない場合、Reflect.defineProperty(1, 'foo')
などのエラーがスローされます。
このメソッドは「Proxy.defineProperty」と組み合わせて使用できます。
const p = 新しいプロキシ({}, {
defineProperty(ターゲット、プロップ、記述子) {
console.log(記述子);
return Reflect.defineProperty(ターゲット、プロップ、記述子);
}
});
p.foo = 'バー';
// {値: "bar"、書き込み可能: true、列挙可能: true、構成可能: true}
p.foo // "バー"
上記のコードでは、Proxy.defineProperty
がプロパティ割り当てのインターセプトを設定し、Reflect.defineProperty
を使用して割り当てを完了します。
Reflect.getOwnPropertyDescriptor(ターゲット, propertyKey)
Reflect.getOwnPropertyDescriptor
は基本的に Object.getOwnPropertyDescriptor
と同等で、指定されたプロパティの説明オブジェクトを取得するために使用され、将来的には後者に置き換わります。
var myObject = {};
Object.defineProperty(myObject, 'hidden', {
値: true、
列挙可能: false、
});
//古い書き方
var theDescriptor = Object.getOwnPropertyDescriptor(myObject, 'hidden');
//新しい書き方
var theDescriptor = Reflect.getOwnPropertyDescriptor(myObject, 'hidden');
Reflect.getOwnPropertyDescriptor
と Object.getOwnPropertyDescriptor
の違いの 1 つは、最初のパラメータがオブジェクトでない場合、Object.getOwnPropertyDescriptor(1, 'foo')
はエラーを報告せず、unknown
を返すのに対し、 Reflect.getOwnPropertyDescriptor( 1, 'foo')
は、パラメーターが不正であることを示すエラーをスローします。
Reflect.isExtensible (ターゲット)
「Reflect.isExtensible」メソッドは「Object.isExtensible」に対応し、現在のオブジェクトが拡張可能かどうかを示すブール値を返します。
const myObject = {};
//古い書き方
Object.isExtensible(myObject) // true
//新しい書き方
Reflect.isExtensible(myObject) // true
パラメータがオブジェクトでない場合、非オブジェクトは本質的に拡張不可能であるため、Object.isExtensible
は false
を返し、Reflect.isExtensible
はエラーを報告します。
Object.isExtensible(1) // false
Reflect.isExtensible(1) // エラーを報告する
Reflect.preventExtensions(ターゲット)
Reflect.preventExtensions
は、オブジェクトを拡張不可能にするために使用される Object.preventExtensions
メソッドに対応します。操作が成功したかどうかを示すブール値を返します。
var myObject = {};
//古い書き方
Object.preventExtensions(myObject) // オブジェクト {}
//新しい書き方
Reflect.preventExtensions(myObject) // true
パラメータがオブジェクトでない場合、ES5 環境では Object.preventExtensions
がエラーを報告し、ES6 環境では渡されたパラメータを返し、Reflect.preventExtensions
がエラーを報告します。
// ES5環境
Object.preventExtensions(1) // エラーレポート
// ES6環境
Object.preventExtensions(1) // 1
//新しい書き方
Reflect.preventExtensions(1) // エラーレポート
Reflect.ownKeys (ターゲット)
Reflect.ownKeys
メソッドはオブジェクトのすべてのプロパティを返すために使用されます。これは基本的に Object.getOwnPropertyNames
と Object.getOwnPropertySymbols
の合計と同等です。
var myObject = {
フー: 1、
バー: 2、
[Symbol.for('baz')]: 3、
[Symbol.for('bing')]: 4、
};
//古い書き方
Object.getOwnPropertyNames(myObject)
// ['foo', 'bar']
Object.getOwnPropertySymbols(myObject)
//[シンボル(baz), シンボル(bing)]
//新しい書き方
Reflect.ownKeys(myObject)
// ['foo', 'bar', Symbol(baz), Symbol(bing)]
Reflect.ownKeys()
メソッドの最初のパラメータがオブジェクトでない場合、エラーが報告されます。
例: プロキシを使用してオブザーバー パターンを実装する
オブザーバー モードは、データ オブジェクトが変更されると自動的に実行されるデータ オブジェクトを自動的に監視する機能を指します。
const person = 観察可能({
名前:「チャン・サン」、
年齢: 20歳
});
関数 print() {
console.log(`${人名}, ${人.年齢}`)
}
観察(印刷);
person.name = '李思';
//出力
// ジョン・ドゥ、20歳
上記のコードでは、データオブジェクト「person」が観測対象、関数「print」が観測者となっています。データオブジェクトが変更されると、print
が自動的に実行されます。
次に、Proxy を使用してオブザーバー パターンの最も単純な実装、つまり 2 つの関数 observable
と observe
を実装します。その考え方は、「observable」関数が元のオブジェクトの Proxy プロキシを返し、代入操作をインターセプトし、オブザーバーとして機能するさまざまな関数をトリガーするというものです。
const queuedObservers = new Set();
constobserver = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});
関数セット(ターゲット、キー、値、受信者) {
const result = Reflect.set(ターゲット、キー、値、受信者);
queuedObservers.forEach(observer => observer());
結果を返します。
}
上記のコードでは、最初に Set
コレクションが定義され、すべてのオブザーバー関数がこのセットに入れられます。次に、「observable」関数は元のオブジェクトのプロキシを返し、割り当てをインターセプトします。インターセプト関数 set
では、すべてのオブザーバーが自動的に実行されます。
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0