JavaScript---エージェントと反射
41202 ワード
引用:エージェントと反射はjavaScriptが他の言語と異なる独自の特性のように聞こえますが、いくつかの面から言えば、エージェントはC++のポインタに似ていますが、ここでは定義について説明しません.次にいくつかの例をあげると、分かりやすいです.
空のエージェントの作成
エージェントはProxyコンストラクション関数を使用して作成され、このコンストラクション関数は2つのオブジェクトを受信し、いずれのパラメータも欠けていると
最も簡単なエージェントは、抽象的なターゲットオブジェクトとして以外に何もしないという上の空のエージェントのように、次のような行為です.
キャプチャの定義
例えば、targetのプロパティにアクセスしようとすると、実際に得られた値のソースは、
上図の太字に注意してください.属性にアクセスしないとしたら?proxyのプロパティ値はhanderで処理されません.
これは通常のオブジェクトに比べて不思議な現象であり,次にhanderオブジェクトとget()キャプチャをさらに理解する.
キャプチャパラメータと反射API
すべてのキャプチャは応答のパラメータにアクセスできます.get()キャプチャは、ターゲットオブジェクト、クエリーするプロパティ、エージェントオブジェクトの3つのパラメータを受信するなど、キャプチャされたメソッドの元の動作を再構築できます.
これらのパラメータを使用すると、キャプチャされた元の動作を再構築できます.
すべてのキャプチャは、独自のパラメータに基づいて元の操作を再構築できますが、get()のようにすべてのキャプチャの動作が簡単ではないため、手書きコードで法のように砲撃する考えは現実的ではありません.
プロセッサ・オブジェクト内のすべてのキャプチャ可能なメソッドには、対応するリフレクションAPIメソッドがあり、このように空のエージェント・オブジェクトを定義することができます.
さらに、
反射処理値を簡単に利用
エージェントの条件-キャプチャ不変
キャプチャを使用すると、ほとんどの基本的な方法の動作を変更できますが、制限はありません.
キャプチャプロセッサの動作は、キャプチャ不変式に従う必要があります.トラップの不変形は方法によって異なります
たとえば、ターゲットオブジェクトに
取り消し可能エージェント
エージェントオブジェクトとターゲットの連絡を中断する必要がある場合があります.
Proxyには、エージェントオブジェクトを作成し、
反射APIとオブジェクトAPI
反射APIを使用する場合は、次のことを覚えておいてください.反射APIは、キャプチャ処理プログラム に限定されない.ほとんどの反射APIメソッドは、Objectタイプに対応するメソッド を有する.
通常、Object上の方法は汎用プログラムに用いられ、反射方法は細粒度のオブジェクト制御と操作に適している.
1.ステータスタグ:
多くの反射メソッドは、実行しようとする操作が成功したかどうかを示す「ステータスタグ」と呼ばれるブール値を返します.ステータスタグは、エラーを投げ出す可能性のある方法よりも役に立つ場合があります.
反射APIで再構築
次の反射方法では、ステータスタグが提供されます.
2.オペレータの代わりに一等関数を使用
次の反射方法では、オペレータのみが実行できる操作を提供します.
Reflect.get():オブジェクト属性アクセス操作法Reflectに代わることができる.set():
例:
エージェント別エージェント
エージェントは、反射APIの操作をブロックできます.これは、ターゲットオブジェクト上に多層ブロックネットワークを構築するために、別のエージェントオブジェクトをエージェントするエージェントオブジェクトを完全に作成できることを意味します.
エージェントの問題と不足
エージェントはECMAScriptの既存のベースに構築された新しいAPIであるため、実際には最善を尽くしています.しかし、場合によっては、エージェントも現在のECMAScriptメカニズムとうまく連携できない場合があります.
1.エージェントのthis
エージェントの現在の問題のソースはthis値です.
多くの場合、これは予想に合致する行為です.しかし、ターゲットオブジェクトがオブジェクトIDに依存している場合、予想外の状況に遭遇する可能性があります.少し曲がった例を見てみましょう.
これは,Userインスタンスが最初にターゲットオブジェクトをWeakMapのキーとして使用していたのに,エージェントオブジェクトが自身からこのインスタンスを取得しようとしたためである.
この問題を解決するには、エージェントを再構成し、エージェントUserインスタンスをエージェントUserクラス自体に変更します.その後エージェントを作成するインスタンスは、そのエージェントインスタンスをWeakMapのキーとして使用します.
もしこの文章があなたに役に立つならば、いいね+コレクション+関心を歓迎して、後でもっと良質な内容を出すことができます
空のエージェントの作成
let target = {
name: 'lihua',
age: 18,
array: [1, 2, 6]
}
let handler = {
}
let proxy = new Proxy(target, handler)
// proxy target ,
console.log(target.array === proxy.array) //true
proxy.age = 45
console.log(target.age === proxy.age) //true
//
console.log(proxy === target) //false : proxy target
//Proxy.prototype undefined
エージェントはProxyコンストラクション関数を使用して作成され、このコンストラクション関数は2つのオブジェクトを受信し、いずれのパラメータも欠けていると
TypeError
が放出されます.最も簡単なエージェントは、抽象的なターゲットオブジェクトとして以外に何もしないという上の空のエージェントのように、次のような行為です.
let a = 'name'
let b = [2, 4]
let target = {
a,
b
}
let proxy = {
a,
b
}
console.log(target.b === proxy.b) //true
console.log(target === proxy) //false
キャプチャの定義
例えば、targetのプロパティにアクセスしようとすると、実際に得られた値のソースは、
get()
のhander
と値を返すget()
キャプチャを定義することができる.let target = {
name: 'lihua'
}
let handler = {
get() {
return 'handle over'
}
}
let proxy = new Proxy(target, handler)
console.log(proxy.name) //handle over
上図の太字に注意してください.属性にアクセスしないとしたら?proxyのプロパティ値はhanderで処理されません.
let target = {
name: 'lihua'
}
let handler = {
get() {
return 'handle over'
}
}
let proxy = new Proxy(target, handler)
console.log(proxy) // { name: 'lihua' }
console.log(proxy.name) // handle over
これは通常のオブジェクトに比べて不思議な現象であり,次にhanderオブジェクトとget()キャプチャをさらに理解する.
キャプチャパラメータと反射API
すべてのキャプチャは応答のパラメータにアクセスできます.get()キャプチャは、ターゲットオブジェクト、クエリーするプロパティ、エージェントオブジェクトの3つのパラメータを受信するなど、キャプチャされたメソッドの元の動作を再構築できます.
let target = {
name: 'lihua',
age: 18,
array: [1, 2, 6]
}
let handler = {
//
get(trapTarget, property, reciver) {
console.log(trapTarget === target)
console.log(property)
console.log(reciver === proxy)
return undefined
}
}
let proxy = new Proxy(target, handler)
// , proxy ,hander get() ,
consoel.log(proxy.age) // get ,
//true
//age
//true
//undefined proxy.age get
これらのパラメータを使用すると、キャプチャされた元の動作を再構築できます.
let target = {
name: 'lihua',
age: 18,
array: [1, 2, 6]
}
let handler = {
get(trapTarget, property, reciver) {
return trapTarget[property]
}
}
let proxy = new Proxy(target, handler)
console.log(proxy.age) //18
すべてのキャプチャは、独自のパラメータに基づいて元の操作を再構築できますが、get()のようにすべてのキャプチャの動作が簡単ではないため、手書きコードで法のように砲撃する考えは現実的ではありません.
プロセッサ・オブジェクト内のすべてのキャプチャ可能なメソッドには、対応するリフレクションAPIメソッドがあり、このように空のエージェント・オブジェクトを定義することができます.
let target = {
name: 'lihua',
age: 18,
array: [1, 2, 6]
}
let handler = {
get(trapTarget, property, reciver) {
return Reflect.get(trapTarget, property, reciver)
}
}
let proxy = new Proxy(target, handler)
console.log(proxy.age) //18
さらに、
hander
は、より簡潔にすることができます.let handler = {
get: Reflect.get
}
反射処理値を簡単に利用
let target = {
word: 'hello'
}
let handler = {
get() {
return Reflect.get(...arguments) + ' world'
}
}
let proxy = new Proxy(target, handler)
console.log(proxy.word) //hello world
エージェントの条件-キャプチャ不変
キャプチャを使用すると、ほとんどの基本的な方法の動作を変更できますが、制限はありません.
キャプチャプロセッサの動作は、キャプチャ不変式に従う必要があります.トラップの不変形は方法によって異なります
たとえば、ターゲットオブジェクトに
のデータ属性がある場合、TypeErrorが放出されます.let target = {
word: 'hello'
}
Object.defineProperty(target, 'age', {
writable: false, //
configurable: false, //
value: 48
})
let handler = {
get() {
return Reflect.get(...arguments) + ' world'
}
}
let proxy = new Proxy(target, handler)
console.log(proxy.age)
//TypeError
取り消し可能エージェント
エージェントオブジェクトとターゲットの連絡を中断する必要がある場合があります.
new Proxy
コンストラクション関数で作成されたオブジェクトがエージェントを取り消すことができない場合は、Proxyには、エージェントオブジェクトを作成し、
revocable
の取り消しメソッドを暴露するためのrevoke
メソッドが暴露されています.revocableメソッドの戻り値は、{「proxy」:proxy,「revoke」:revoke}という構造のオブジェクトです.Proxy.revocable
は、エージェントオブジェクトとターゲットとの関連付けを取り消すために使用され、エージェントを取り消す操作は不可逆的である.let target = {
word: 'hello'
}
let handler = {
get() {
return Reflect.get(...arguments) + ' world'
}
}
let {
proxy, revoke } = Proxy.revocable(target, handler)
console.log(proxy.word) //hello world
revoke()
console.log(proxy.word) //TypeError
反射APIとオブジェクトAPI
反射APIを使用する場合は、次のことを覚えておいてください.
通常、Object上の方法は汎用プログラムに用いられ、反射方法は細粒度のオブジェクト制御と操作に適している.
1.ステータスタグ:
多くの反射メソッドは、実行しようとする操作が成功したかどうかを示す「ステータスタグ」と呼ばれるブール値を返します.ステータスタグは、エラーを投げ出す可能性のある方法よりも役に立つ場合があります.
let o = {
}
Object.freeze(o)
try {
Object.defineProperty(o, 'name', {
value: 'lihua' })
} catch (error) {
console.log('error')
}
//error
反射APIで再構築
const o = {
}
Object.freeze(o)
if (Reflect.defineProperty(o, 'name', {
value: 'lihua' })) {
console.log('success')
} else {
console.log('fail')
}
//fail
次の反射方法では、ステータスタグが提供されます.
Reflect.defineProperty()
Reflect.preventExtensions()
Reflect.setPrototypeOf()
Reflect.set()
Reflect.deleteProperty()
2.オペレータの代わりに一等関数を使用
次の反射方法では、オペレータのみが実行できる操作を提供します.
Reflect.get():オブジェクト属性アクセス操作法Reflectに代わることができる.set():
=
の代入オペレータReflectを代替することができる.has():in
オペレータまたはwith()
Reflectに代わることができる.deleteProperty():delete
オペレータReflectの代わりに使用できます.construct():new
オペレータの代わりに使用できます.例:
let o = {
name: 'ming'
}
// Reflect.get():
console.log(Reflect.get(o, 'name')) //ming
// Reflect.set(): =
Reflect.set(o, 'age', 18)
// Reflect.has(): in with()
console.log(Reflect.has(o, 'age')) //true
// Reflect.deleteProperty(): delete
console.log(Reflect.deleteProperty(o, 'name')) //true
// Reflect.construct(): new
console.log(Reflect.construct(Array, [2, 5, 6])) //[ 2, 5, 6 ]
エージェント別エージェント
エージェントは、反射APIの操作をブロックできます.これは、ターゲットオブジェクト上に多層ブロックネットワークを構築するために、別のエージェントオブジェクトをエージェントするエージェントオブジェクトを完全に作成できることを意味します.
let target = {
name: 'lihua'
}
let firstProxy = new Proxy(target, {
get() {
console.log('first proxy')
return Reflect.get(...arguments)
}
})
let secondProxy = new Proxy(firstProxy, {
get() {
console.log('second proxy')
return Reflect.get(...arguments)
}
})
console.log(secondProxy.name)
//second proxy
//first proxy
//lihua
エージェントの問題と不足
エージェントはECMAScriptの既存のベースに構築された新しいAPIであるため、実際には最善を尽くしています.しかし、場合によっては、エージェントも現在のECMAScriptメカニズムとうまく連携できない場合があります.
1.エージェントのthis
エージェントの現在の問題のソースはthis値です.
let target = {
thisVal() {
console.log(this === proxy)
console.log(this === target)
}
}
let proxy = new Proxy(target, {
})
proxy.thisVal()
// true
// false
target.thisVal()
// false
// true
多くの場合、これは予想に合致する行為です.しかし、ターゲットオブジェクトがオブジェクトIDに依存している場合、予想外の状況に遭遇する可能性があります.少し曲がった例を見てみましょう.
const wm = new WeakMap()
class User {
constructor(userId) {
wm.set(this, userId)
}
set id(userId) {
wm.set(this, userId)
}
get id() {
return wm.get(this)
}
}
const user = new User(123)
const proxy = new Proxy(user, {
}) // this
console.log(proxy.id)
//undefined
これは,Userインスタンスが最初にターゲットオブジェクトをWeakMapのキーとして使用していたのに,エージェントオブジェクトが自身からこのインスタンスを取得しようとしたためである.
この問題を解決するには、エージェントを再構成し、エージェントUserインスタンスをエージェントUserクラス自体に変更します.その後エージェントを作成するインスタンスは、そのエージェントインスタンスをWeakMapのキーとして使用します.
const wm = new WeakMap()
class User {
constructor(userId) {
wm.set(this, userId)
}
set id(userId) {
wm.set(this, userId)
}
get id() {
return wm.get(this)
}
}
const UserClassProxy = new Proxy(User, {
})
const proxyUser = new UserClassProxy(123)
console.log(proxyUser.id) //123
もしこの文章があなたに役に立つならば、いいね+コレクション+関心を歓迎して、後でもっと良質な内容を出すことができます