【JavaScript】Proxyってなんすか?
こんにちは!
スマレジ テックファームのMichiです!
突然ですが、Vue.jsのコードでreactive
なオブジェクトをconsole.log
したらこんな値が返ってきます。
「このProxyってやつ、なんすか?」とずっと思っていたので、調べてみることにしました!
Proxyとは?
公式ドキュメントでは ...
MDNのドキュメントにはこのように記載があります。
Proxy オブジェクトにより別なオブジェクトのプロキシを作成することができ、そのオブジェクトの基本的な操作を傍受したり再定義したりすることができます。
「なんのこっちゃ???」って感じですよね。これで理解できるなら苦労せんて。
というわけで、もう少し嚙み砕いて説明してみます。
ひと言で説明すると...
Proxyとは「元のオブジェクトの動作をカスタマイズするためのオブジェクト」です。
例を見てみましょう。
// 元のオブジェクト const data = { red: '赤色', yellow: '黄色'} // Proxyで元のオブジェクトをカスタマイズする const proxy = new Proxy(data, { get(target, prop) { return 'hello' } }) console.log(data.red) // 結果:赤色 console.log(proxy.red) // 結果:hello
元のオブジェクトdata.red
には赤色
という値が格納されているにもかかわらず、Proxyオブジェクトでラップしたproxy.red
を呼び出すと、元のオブジェクトには存在しないhello
という文字列が返ってきます。これが上で書いた「元のオブジェクトの動作をカスタマイズする」ということです。
ちなみに、Proxyは直訳すると「代理」という意味になります。元のオブジェクトの代わりに、処理を「代理」で行ってくれているというわけですね。
使い方
基本構文
new Proxy(target, handler)
引数
target
: 動作をカスタマイズされる側のオブジェクトhandler
: ターゲットの動作を定義するためのオブジェクト
Proxyオブジェクトはnew
演算子で初期化し呼び出します。第1引数にターゲット
、 第2引数にはハンドラー
を取ります。ハンドラー
で定義できるメソッドは決まっており、具体的には以下の表の通りとなります。
このハンドラーで定義できるメソッドのことをトラップ
と呼称したりもします。今回はこの中でも代表的なトラップである、get
とset
について見ていきます。
getトラップ
最初の例でも出てきましたが、get
はプロパティが取得されたときに呼び出されるトラップです。
基本構文
get(target, prop, receiver) { // プロパティを取得したときに実行する処理 }
引数
target
: 元のオブジェクト(new Proxy
の第一引数と同じ)prop
: オブジェクトのプロパティ名receiver
: proxyオブジェクト自身(今回は使わない)
戻り値
- 任意の値
具体例
以下は、存在しないプロパティを取得しようとした際エラーとなる実装です。
const data = { red: "赤色", yellow: "黄色" } const proxy = new Proxy(data, { get(target, prop) { if (prop in target) { return target.prop } else { throw new Error("存在しないプロパティです") } } }) console.log(proxy.blue) // 結果:存在しないプロパティです
setトラップ
set
はプロパティを設定するときに呼び出されるトラップです。
基本構文
set(target, prop, value, receiver) { // プロパティを設定するときに実行する処理 }
引数
target
: 元のオブジェクト(new Proxy
の第一引数と同じ)prop
: オブジェクトのプロパティ名value
: 新たに設定するプロパティの値receiver
: proxyオブジェクト自身(今回は使わない)
戻り値
- 真偽値(設定が成功すると
true
、失敗するとfalse
を返す)
具体例
以下は、文字列以外をプロパティに設定しようとした際エラーとなる実装です。
const data = { red: "赤色", yellow: "黄色" } const proxy = new Proxy(data, { set(target, prop, value) { if (typeof value !== "string") { throw new Error("設定できるのは文字列のみです") return false } else { target.prop = value return true } } }) proxy.red = 1 // 結果:設定できるのは文字列のみです
他にも様々なトラップが存在します。気になる方は、公式ドキュメントなどで調べてみるとよいでしょう。
ユースケース
Proxyを使ったユースケースには、様々なものが考えられます。以下はその例です。
- デフォルト値の取得 ... 存在しないオブジェクトのプロパティを取得しようとした時にデフォルトの値を返す。
- 大文字⇔小文字の変換 ... プロパティの取得・設定時に大文字/小文字のどちらか一方へ変換することによって、大文字/小文字の区別をなくす。
- バリデーション ... プロパティの設定時にバリデーションを設定して、不正な値をはじく。
とは言いつつ、実際に自分でProxyオブジェクトを作成する機会はあまりないでしょう。一番多いのは、外部ライブラリやフレームワークの中で使用されているパターンです。
冒頭でも書いたように、Vue.jsのreactive
オブジェクトをconsole.log
するとProxyオブジェクトが返されます。これは、 Vue.js におけるリアクティブ性は Proxy オブジェクトにより実現されているからです。
まとめ
JavaScriptのProxyについて解説しました。
自分でProxyを使う機会はなかなかないかもしれませんが、フレームワークからProxyが返ってきたときに「なにこれ!?」ってならないように、勉強していきたいですね。