---
# System prepended metadata

title: JS Proxy(代理)筆記
tags: [Javascript]

---

---
tags: Javascript
---

# JS Proxy(代理)筆記

對`Proxy`進行操作，會先經過`Proxy`作用在`target`身上，可以讓資料在存取前進行一些操作

在`Vue`中就有使用`Proxy`來組成資料，達成資料雙向綁定的特性。

語法如下:

`var p = new Proxy(target, handler);`

`target`: 只能是物件，而且並非是複製一份而是指向同個位置

`handler`: 定義在操作行為上的函數

### 基本用法

`get`函式取值，`set`函式設值

```javascript=
var handler = {
    get: function(obj, prop) {
        console.log(`${obj}, ${prop}`);
        // 取值
        return obj[prop];
    },
    set: function(obj, prop, newVal) {
        console.log(`${obj}, ${prop}, ${newVal}`);
        // 基本設值
        obj[prop] = newVal;

        // 表示成功，沒寫console會有錯誤
        return true;
    }
};

var p = new Proxy({a: 1}, handler);

p.a = 2;
console.log(p.a); // 1
```
`set`函式輸出`{a: 1} , a, 2`
`get`函式輸出`{a: 2}, a`

### 驗證

可以在`set`函式中對值進行驗證

```javascript=
let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('年齡不是整數');
      }
      if (value > 200) {
        throw new RangeError('年齡無效');
      }
    }

    // 設值
    obj[prop] = value;

    // 表示成功
    return true;
  }
};

let person = new Proxy({}, validator);

person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // 拋出異常
person.age = 300; // 拋出異常
```

### 模仿資料雙向綁定

效果如下圖:

![](https://i.imgur.com/Vha1m7w.gif)

```htmlembedded=
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">

    </div>

    <script>
        function render(key, value) {
            document.getElementById('app').innerHTML = `${key}: ${value}`;
        }

        var handler = {
            get: function(obj, prop) {
                console.log(`${obj}, ${prop}`);
                // 取值
                return obj[prop];
            },
            set: function(obj, prop, newVal) {
                console.log(`${obj}, ${prop}, ${newVal}`);
                // 基本設值
                obj[prop] = newVal;
                render(prop, obj[prop]);
                // 表示成功，沒寫console會有錯誤
                return true;
            }
        };

        var p = new Proxy({}, handler);
        p.name = 'John';
        setTimeout(() => {
            p.name = 'Joe';
        }, 2000);
        
    </script>
  </body>
</html>
```