LoginSignup
3
1

More than 1 year has passed since last update.

JavaScript Proxyの使い方

Last updated at Posted at 2022-04-17

Proxyとは

Proxyを使うことで元のObjectのproxy(代理)として処理を中継できます。
元の処理以外の処理を追加することで、元のObjectに影響を与えずにObjectを再定義することができます。

Proxyの作成

//Proxyオブジェクトのコントラクタの第一引数に元のObject、第二引数に元のObjectへの追加処理(ハンドラ)をわたします。
const proxy = new Proxy(target, handler);
//追加処理がない場合でも空のハンドラオブジェクトが必要です。
const array = [1,2,3,4,5];
const sample_proxy = new Proxy(array, {});
console.log(sample_proxy); // => [ 1, 2, 3, 4, 5 ]

トラップの設定

ハンドラオブジェクトにトラップ(=メソッド)を設定することで処理を割り込ませることができます。

const student = {
  name: 'Tanaka',
  age: 18,
  major: 'Math'
};

const proxy = new Proxy(student, {});
//ハンドラは空なので、プロキシは元のターゲットと同じ動作をします。
console.log(student.name); // => Tanaka
console.log(proxy1.name); // => Tanaka

//get()トラップを使うことでプロパティの値の取得に割り込みをします。
const handler1 = {
  get(target, prop, receiver){
    return target[prop].toUpperCase()
  },
};

const proxy1 = new Proxy(student, handler1);
console.log(proxy1.name); // => TANAKA
//handler1のget(target, prop, receiver)について、
//この場合targetはstudent、propはname、receiverは{ name: 'Tanaka', age: 18, major: 'Math' }となります。

プロパティへのアクセスのカスタマイズ

set()トラップを使用してプロパティへのアクセスをカスタマイズができます。
数字1桁、小数点第2位までの数字を受け付けそれ以外はエラーを返す配列インスタンスのproxyを作成してみます。

const numbers = [1, 2.0, 3.11];

const proxy = new Proxy(numbers, {
    set(target, prop, value) {
    const pattern = /^[0-9]{0,1}(\.[0-9]{1,2})?$/
    if (!pattern.test(value)) {
        throw new Error('Illegal Pattern');
       }
    target[prop] = value;
    }
})

proxy[0] = 1.0;
proxy[1] = 2.1;
proxy[2] = 3.12;
console.log(proxy) // => [ 1, 2.1, 3.12 ]
proxy[3] = 3.111;  // => Error: Illegal Pattern

Reflectの使用

Reflectクラスを使うことで簡単に元のオブジェクトへの操作を呼ぶことができます。

const student = {
  name: 'Tanaka',
  age: 18,
  major: 'Math'
};

//ownKeysメソッドで元のオブジェクトが所有するキーの返却ができます。
console.log(Reflect.ownKeys(student)); // => [ 'name', 'age', 'major' ]

//handler1と同じくget()トラップを使いpropを大文字にしますが、propがnameの時だけに限定し、
//他は元のオブジェクトのプロパティを返します。
const handler2 = {
  get(target, prop, receiver){
    if (prop === 'name') {
      return target[prop].toUpperCase();
    }
    return Reflect.get(target, prop);
  },
};

const proxy2 = new Proxy(student, handler2);
console.log(proxy2.name); // => TANAKA
console.log(proxy2.age); // => 18
console.log(proxy2.major); // => Math

proxyを使用した関数への割り込み

apply()トラップを使用することで、関数の呼び出しに割り込むことができます。

  const multiply = (a, b) => {
    return a * b;
  }
  
  const handler = {
    apply(target, thisArg, argumentsList) {
      console.log(target); //=> [Function: multiply]
      console.log(target(4,8)); //=> 32
      console.log(thisArg); //=> undefined
      console.log(argumentsList); // => [4, 8]
      return target(argumentsList[0] ** 2, argumentsList[1] ** 2);
      // 下記に入れ替えても同じ結果が得られる
      // return target.apply(thisArg, argumentsList.map(num => num ** 2));
    }
  };
  
  const proxy = new Proxy(multiply, handler);
  console.log(proxy(4, 8)); => 1024
  //handlerのapply(target, thisArg, argumentsList)について、
  //この場合targetはmultipy関数、thisArgこの呼び出しに対するthis引数
  //argumentsListはこの呼び出しに対する引数リストとなります。
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1