JS Proxy(代理)筆記

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

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

語法如下:

var p = new Proxy(target, handler);

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

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

基本用法

get函式取值,set函式設值

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函式中對值進行驗證

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; // 拋出異常

模仿資料雙向綁定

效果如下圖:

<!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>