代理(拦截器)是对象的访问控制,setter/getter
是对单个对象属性的控制,而代理是对整个对象的控制。
- 读写属性时代码更简洁
- 对象的多个属性控制统一交给代理完成
- 严格模式下
set
必须返回布尔值
语法
const p = new Proxy(target, handler)
参数
target
要使用 Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为。
基本用法
// "use strict"
let zs = {
name: "张三"
}
let proxy = new Proxy(zs, {
get(obj, property) {
return obj[property]
},
set(obj, property, value) {
obj[property] = value;
// return true 严格模式下,要返回一个布尔值
}
})
console.log(proxy) // Proxy {name: "张三"}
console.log(proxy.name) // 张三
proxy.name = "李四";
console.log(proxy.name) // 李四
代理函数
如果代理以函数方式执行时,会执行代理中定义 apply
方法。
apply
参数:函数,上下文对象,参数
function factorial(num) {
return num === 1 ? 1 : num * factorial(num - 1)
}
let proxy = new Proxy(factorial, {
apply(func, that, args) {
console.log("我来啦")
console.log(func)
console.log(that)
console.log(args)
}
})
proxy()
输出的参数是数组
尝试改变 proxy 的 this 指向,并传递参数
proxy.call(this, 5)
实现阶乘
apply(func, that, args) {
let jc = func(args[0]);
/* 也可以这样
let jc = func.apply(null, args); */
console.log(jc) // 120
}
代理数组
const lessons = [
{
title: "媒体查询响应式布局",
category: "css"
},
{
title: "FLEX 弹性盒模型",
category: "css"
},
{
title: "MYSQL多表查询随意操作",
category: "mysql"
}
];
let proxy= new Proxy(lessons, {
get(array, index) {
console.log(array);
console.log(index);
}
})
proxy[0]
截取字符
let proxy = new Proxy(lessons, {
get(array, index) {
let { title } = array[index];
array[index].title = title.length > 6 ?
title.substring(0, 6) + '.'.repeat(3) : title
return array[index]
}
})
console.log(proxy[2])
类似 v-model 实现数据双向绑定
我也将要发生改变
function View() {
let proxy = new Proxy({}, {
get(obj, property) {
return obj[property]
},
set(obj, property, value) {
console.log("我来啦");
console.log(property, value) // 二、输出 title 和 输入框的值
}
})
this.init = function() {
const els = document.querySelectorAll("[v-model]");
els.forEach(item => {
item.addEventListener("keyup", function() {
proxy[this.getAttribute("v-model")] = this.value; // 一、这里触发后会走 setter
})
})
}
}
let view = new View();
view.init();
页面渲染
set(obj, property, value) {
document.querySelectorAll(`[v-model="${property}"]`)
.forEach(item => {
item.value = value
})
document.querySelectorAll(`[v-bind="${property}"]`)
.forEach(item => {
item.innerHTML = value
})
}