JSのProxyで無量空処する

ProxyはES6から使えるようになった新しい**術式**です。
この**術式**は非常に強力で、Proxyで包み込んだ**人や呪霊の行う様々なアクション(術式の発動など)をトラップ**して、**特定の処理を術式発動までの間に挟み込む事**ができます。

一種の**結界術**のようなものだと思っていただければ良いかと思います。

この記事ではこの強力な**術式**を使って、現代最強の呪術師である五条悟の使う**領域展開「無量空処」**を再現してみたいと思います。

### 五条悟も最初から最強だったわけではない

まずはじめに、無下限呪術を覚えていない頃の五条悟に登場してもらいます。敵役はもちろん漏瑚です。

```index.js
const 五條悟 = {
  name: "五條悟",
};

const 漏瑚 = {
  name: "漏瑚",
  "極ノ番「隕」"(target) {
    console.log("極ノ番「隕」発動！！");
    console.log(target.name + "は死ぬ");
    target.name = "死体";
  },
  蓋棺鉄囲山(target) {
    console.log("蓋棺鉄囲山発動！！");
    console.log(target.name + "は死ぬ");
  },
};

// 蓋棺鉄囲山で五条悟を攻撃する
漏瑚.蓋棺鉄囲山(五条悟);

```

これを実行してみると、当たり前ですが、五条悟は死にます。

```
$ node index.js 
蓋棺鉄囲山発動！！
五条悟は死ぬ
```

### そして五条悟は最強と成った

無量空処は、**無下限の内側を展開し、相手の知覚、伝達、生きるという行為に無限回の作業を強制する術式**です。つまり無量空処の内側では、術式を発動するまでに無限回の作業が必要になってしまい、結果術式を発動できなくなるわけですね。

これをProxyを使って再現すると、以下のようになります。

``` inde.js
const 無量空処の術式2 = {
  apply(target, thisArg, argumentsList) {
    // 無下限呪術を適用した関数（術式の発動）に無限回の施行を要求する
    while (true) {
      console.log(target.name + "するぞ！");
    }
    return target(...argumentsList);
  },
};

const 無量空処の術式 = {
  get(target, prop) {
    if (typeof target[prop] === "function") {
      return new Proxy(target[prop], 無量空処の術式2);
    }
  },
};

const 五条悟 = {
  name: "五条悟",
  /**
   * 領域展開「無量空処」
   * 領域に引きずり込んだ相手は術式発動のために無限回の施行が要求されるようになる
   * @param {*} target 領域に引きずり込む相手
   */
  無量空処(target) {
    return new Proxy(target, 無量空処の術式);
  },
};
```

「無量空処」の術式は２段階の術式です。１段階目の術式(無量空処の術式)で、敵の術式発動に干渉し、敵の術式発動までの間に２段目の術式を挟み込みます

```.js
const 無量空処の術式 = {
  get(target, prop) {
    // 敵が術式を発動する場合（functionを実行する場合）はその術式をProxy術式でラップする
    if (typeof target[prop] === "function") {
      return new Proxy(target[prop], 無量空処の術式2);
    }
  },
};

```

2段階目の術式では、**術式発動に無限回の作業を強制します。**ある意味これが無下限呪術の本体ですね

```.js
const 無量空処の術式2 = {
  apply(target, thisArg, argumentsList) {
    // 無下限呪術を適用した関数（術式の発動）に無限回の作業を要求する
    while (true) {
      console.log(target.name + "するぞ！");
    }
    // オリジナルの術式の発動（ここにたどり着くことはない）
    return target(...argumentsList);
  },
};
```

無量空処を覚えた五条悟であれば、漏瑚など敵ではありません。以下を実行してみましょう

```.js


const 無量空処の術式2 = {
  apply(target, thisArg, argumentsList) {
    // 無下限呪術を適用した関数（術式の発動）に無限回の施行を要求する
    while (true) {
      console.log(target.name + "するぞ！");
    }
    return target(...argumentsList);
  },
};

const 無量空処の術式 = {
  get(target, prop) {
    if (typeof target[prop] === "function") {
      return new Proxy(target[prop], 無量空処の術式2);
    }
  },
};

const 五条悟 = {
  name: "五条悟",
  /**
   * 領域展開「無量空処」
   * 領域に引きずり込んだ相手は術式発動のために無限回の施行が要求されるようになる
   * @param {*} target 領域に引きずり込む相手
   */
  無量空処(target) {
    return new Proxy(target, 無量空処の術式);
  },
};

const 漏瑚 = {
  name: "漏瑚",
  "極ノ番「隕」"(target) {
    console.log("極ノ番「隕」発動！！");
    console.log(target.name + "は死ぬ");
    target.name = "死体";
  },
  蓋棺鉄囲山(target) {
    console.log("蓋棺鉄囲山発動！！");
    console.log(target.name + "は死ぬ");
  },
};

const 無量空処を食らった漏瑚 = 五条悟.無量空処(漏瑚);

無量空処を食らった漏瑚.蓋棺鉄囲山(五条悟);
```

実行すると以下のようになります。

![無量空処.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93999/c81d1e3a-171e-08c0-bd25-85519db10492.gif)

蓋棺鉄囲山の発動に無限回の作業が必要になってしまっていますね。

この術式はとても強力なので、**相手が誰だろうが、どんな術式を持っていようが関係なく発動**します。例えば真人相手でも

```.js
const 真人 = {
  name: "真人",
  無為転変(target) {
    console.log("無為転変発動！！");
    console.log(target.name + "は死ぬ");
  },
  自閉円頓裹(target) {
    console.log("自閉円頓裹発動！！");
    console.log(target.name + "は死ぬ");
  },
};

const 無量空処を食らった真人 = 五条悟.無量空処(真人);

無量空処を食らった真人.無為転変(五条悟);
```
こうなります
![無量空処2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93999/58afff63-5a38-5f0a-abb4-4e673e001044.gif)


### もうあの人1人で良くないですか？

今回作った五条悟は、無量空処の領域内に取り込んだ相手からの術式を受けなくなりますが、領域外にいる相手からの攻撃は依然受けてしまいます。

以下を実行してみましょう

```index.js
const 五条悟 = {
  name: "五条悟",
  /**
   * 領域展開「無量空処」
   * 領域に引きずり込んだ相手は術式発動のために無限回の施行が要求されるようになる
   * @param {*} target 領域に引きずり込む相手
   */
  無量空処(target) {
    return new Proxy(target, 無量空処の術式);
  },
};

const 漏瑚 = {
  name: "漏瑚",
  "極ノ番「隕」"(target) {
    console.log("極ノ番「隕」発動！！");
    console.log(target.name + "は死ぬ");
    target.name = "死体";
  },
  蓋棺鉄囲山(target) {
    console.log("蓋棺鉄囲山発動！！");
    console.log(target.name + "は死ぬ");
  },
};

// 無量空処を発動しない
漏瑚.蓋棺鉄囲山(五条悟);
```

![無量空処3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93999/b70357f6-e882-dd2c-5b32-d834b1e4a0b2.gif)

しかし五条悟には**無下限呪術**があります。これを自身の周囲に展開することで、**攻撃が自身に到達するまでに無限回の作業を強制**することができます。

この**無下限呪術**もProxyを使って再現することができます。

```.js
const 無下限呪術 = {
  get(target, prop) {
    while (true) {
      console.log("五条悟に触れることはできない・・・");
    }
  },
  set(target, prop) {
    while (true) {
      console.log("五条悟に触れることはできない・・・");
    }
  },
};

const 五条悟 = new Proxy(
  {
    name: "五条悟",
    /**
     * 領域展開「無量空処」
     * 領域に引きずり込んだ相手は術式発動のために無限回の施行が要求されるようになる
     * @param {*} target 領域に引きずり込む相手
     */
    無量空処(target) {
      return new Proxy(target, 無量空処の術式);
    },
  },
  // 無下限呪術を自身の周囲に展開する
  無下限呪術
);
```

先程までは相手に無下限呪術を展開していたわけですが、今回は**自身の周囲に展開**します。

この状態でもう一度、蓋棺鉄囲山で五条悟を攻撃してみましょう

```.js
const 無下限呪術 = {
  get(target, prop) {
    while (true) {
      console.log("五条悟に触れることはできない・・・");
    }
  },
  set(target, prop) {
    while (true) {
      console.log("五条悟に触れることはできない・・・");
    }
  },
};

const 五条悟 = new Proxy(
  {
    name: "五条悟",
    /**
     * 領域展開「無量空処」
     * 領域に引きずり込んだ相手は術式発動のために無限回の施行が要求されるようになる
     * @param {*} target 領域に引きずり込む相手
     */
    無量空処(target) {
      return new Proxy(target, 無量空処の術式);
    },
  },
  // 無下限呪術を自身の周囲に展開する
  無下限呪術
);

const 漏瑚 = {
  name: "漏瑚",
  "極ノ番「隕」"(target) {
    console.log("極ノ番「隕」発動！！");
    console.log(target.name + "は死ぬ");
    target.name = "死体";
  },
  蓋棺鉄囲山(target) {
    console.log("蓋棺鉄囲山発動！！");
    console.log(target.name + "は死ぬ");
  },
};

// 無量空処されていない漏瑚で攻撃
漏瑚.蓋棺鉄囲山(五条悟);
```
すると以下のようになります。漏瑚の攻撃は五条悟に無事届かなくなりました。無量空処なんて使わなくても五条悟は最強ってことですね

![無下限呪術.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93999/f3be0d96-65ac-ac25-baa4-3a8b4a87a58d.gif)

ちなみにこの無下限呪術は非常に強力で、極ノ番「隕」のような**代入処理にも干渉できます。**すごい

```.js
  "極ノ番「隕」"(target) {
    console.log("極ノ番「隕」発動！！");
    // 相手は死体になる
    target.name = "死体"; // targetが無下限呪術を発動している場合はこの処理が終わることはない
  },
```

### まとめ

今回紹介したのは、Proxy呪術のごく一部です。今回は、変数の取得 / 代入 / 関数の実行に対してトラップを仕掛けましたが、他にも new演算子へのトラップ / in演算子へのトラップ / ownKeysへのトラップなどオブジェクトに対する様々な操作をトラップできます。詳しくは以下を見てみてください。
[Proxy - JavaScript - MDN Web Docs -](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

現実世界で今回作ったような無下限呪術を使ってしまうと、**動作しているシステムが五条悟という情報を処理しきれず止まってしまいます**し、Proxy呪術自体もメタプロチックでわかりにくいコードを生む原因になりがちなので、採用には慎重になったほうが良いと思いますが、とてもおもしろい技術なので、もしよければみなさんもオリジナルの術式を作ってみてください

最後に、**芥見下々先生、本当にすいませんでした**