JavaScriptのProxyを使いこなそう
最近、ReactやVueなどVirtualDOMを使った技術がトレンドになっています。VirtualDOMの特徴として、DOMの状態を管理から開放されて、変数を変えるだけで自動的に表示に反映される仕組みがあります。
変数の変更を感知し、表示に反映するために使われるのがProxyになります。VirtualDOMに限らず使える場面が多いオブジェクトなので、ぜひ使い方を覚えましょう。
基本的な使い方
Proxyはオブジェクトまたは配列に対してしか使えません。単なる数字や文字列では使えないので注意してください。以下はごく基本的なコードです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const obj = {}; | |
const p = new Proxy(obj, { | |
get: (target, name) => { | |
console.log(`(get) target : ${JSON.stringify(target)}, name: ${name}`); | |
return target[name]; | |
}, | |
set: (target, name, value) => { | |
console.log(`(set) target : ${JSON.stringify(target)}, name: ${name}`); | |
target[name] = value; | |
} | |
}); | |
p.a = "hello"; | |
p.a | |
// -> hello |
まずProxyは既存の変数にとハンドラーを引数に取ります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const obj = {}; | |
const p = new Proxy(obj, handler); |
handlerはget/setを基本としたオブジェクトになります。値を追加した時にset、アクセスした際にgetがコールされます。targetは元のオブジェクト(obj)で、nameはアクセスしようとしたメソッド名(またはキー)になります。そしてvalueとして適用しようとした値が送られます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set: (target, name, value) => { | |
target[name] = value; | |
} |
getはターゲットと実行するメソッド名(またはキー)が送られてきます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set: (target, name, value) => { | |
target[name] = value; | |
} |
配列の場合
Proxyはオブジェクトだけでなく配列にも使えます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ary = []; | |
const q = new Proxy(ary, { | |
get: (target, name) => { | |
console.log(`(get) target : ${JSON.stringify(target)}, name: ${name}`); | |
return target[name]; | |
}, | |
set: (target, name, value) => { | |
console.log(`(set) target : ${JSON.stringify(target)}, name: ${name}`); | |
target[name] = value; | |
} | |
}); | |
q.push('a'); | |
q.push('b'); | |
q.push('c'); | |
console.log(q[0]); |
使い方はオブジェクトの時と変わりません。ただし、配列の中にオブジェクトがあった場合、そのオブジェクトの中を変えても通知されないので注意が必要です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
q.push({ | |
a: 'b', | |
c: 'd' | |
}); | |
// 以下は通知されません | |
q[3].a = 'e'; |
他のオブジェクト
他のオブジェクト(関数、クラス)などに対してもProxyが使えます。ただしクラスなどでインスタンスに対して適用したい場合は、クラスではなくインスタンスに対してProxyを適用する必要があります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Animal { | |
constructor() { | |
this.name = ''; | |
} | |
setName(name) { | |
this.name = name; | |
} | |
getName() { | |
return this.name; | |
} | |
} | |
const dog = new Proxy(new Animal, { | |
get: (target, name) => { | |
console.log(`(class get) target : ${JSON.stringify(target)}, name: ${name}`); | |
return target[name]; | |
}, | |
set: (target, name, value) => { | |
console.log(`(class set) target : ${JSON.stringify(target)}, name: ${name}`); | |
target[name] = value; | |
} | |
}); | |
dog.setName('dog'); | |
console.log(dog.getName()); |
Proxyを使うと、データを更新した時に関連するデータや表示をまとめて更新するといったことが簡単にできます。また、値を判別して例外を出すことで入力チェックのように使うこともできます。
ぜひProxyを使って関連する処理をまとめてみてください。
コメントは受け付けていません。