认识 Proxy 代理
Reflect: MDN文档链接
Proxy: MDN文档链接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
const obj = { a: 1, b: 2 }
// 创建一个 Proxy 代理
const proxy = new Proxy(obj, {
// 设置属性值操作的捕获器
set(target, property, value, receiver) {
// console.log(target, properKey, value)
// target[properKey] = value
console.log('get', target, property, value, receiver)
Reflect.set(target, property, value, receiver)
},
// 用于拦截对象的读取属性操作
get(target, properKey, value, reveiver) {
if (Reflect.has(target, properKey)) {
// 如果读取的值存在 则返回
return Reflect.get(target, properKey)
} else {
// 反之则返回 -1
return -1
}
},
// 手动修改 has 假设一直为 false
has(target, properKye) {
return false
},
})
proxy.a = 10
console.log('obj', obj, 'proxy', proxy)
console.log('b' in proxy)
</script>
</body>
</html>
应用-观察者模式
使用Object.defineProperty实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script>
function observer(target) {
const ob = {}
const div = document.querySelector('#container')
const props = Object.keys(target)
for (const prop of props) {
Object.defineProperty(ob, prop, {
get() {
return target[prop]
},
set(val) {
target[prop] = val
__render()
},
enumerable: true
})
}
__render()
function __render() {
let html = ''
for (const prop of Object.keys(ob)) {
html += `
<p>
${prop}: ${ob[prop]}
</p>
`
}
div.innerHTML = html
}
return ob
}
const target = { name: '张三', age: 18 }
const ob = observer(target)
</script>
</body>
</html>
使用Proxy实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="container"></div>
<script>
function observer(target) {
const div = document.querySelector('#container')
const proxy = new Proxy(target, {
get(target, prop, value) {
return Reflect.get(target, prop)
},
set(taget, prop, val) {
Reflect.set(target, prop, val)
__render()
},
})
__render()
// 渲染函数
function __render() {
let html = ''
for (const prop of Object.keys(target)) {
html += `
<p>
${prop}: ${target[prop]}
</p>
`
}
div.innerHTML = html
}
return proxy
}
const target = { name: '张三', age: 18 }
const ob = observer(target)
// 修改 ob 的属性时
</script>
</body>
</html>
应用-偷懒的构造函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
class User {
// 通过 proxy 代理完成以下操作
// constructor(firstname, lastname, age) {
// this.firstname = firstname
// this.lastname = lastname
// this.age = age
// }
}
function ConstructorProxy(Class, ...propNames) {
return new Proxy(Class, {
construct(target, argumentList) {
const obj = Reflect.construct(target, argumentList)
// 循环统一赋值
propNames.forEach((name, i) => (obj[name] = argumentList[i]))
return obj
},
})
}
// 返回一个代理的构造函数
const UserProxy = ConstructorProxy(User, 'firstname', 'lastname', 'age')
const u = new UserProxy('张', '三', 18)
console.log(u)
</script>
</body>
</html>
应用-可验证的函数参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function sum(a, b) {
return a + b
}
function validatorFun(fun, ...types) {
return new Proxy(fun, {
apply(target, thisArg, argArr) {
types.forEach((type, index) => {
if (typeof argArr[index] !== types[index]) {
throw new TypeError(
`第 ${index + 1} 个参数 ${argArr[index]} 的类型不正确, 期待的类型为 ${types[index]}, 得到的类型则是 ${typeof argArr[index]}`
)
}
})
return Reflect.apply(target, thisArg, argArr)
},
})
}
const sumProxy = validatorFun(sum, 'number', 'number')
console.log(sumProxy(1, 'a'))
</script>
</body>
</html>