Proxy作为库的设计者和框架设计者专用的功能 用于修改某些操作的默认行为,等同于在语言层面做出修改。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
Proxy有两个参数一个是原始的对象 一个是用来定制拦截的行为
A Proxy is created with two parameters:
target: the original object which you want to proxy
handler: an object that defines which operations will be intercepted and how to redefine intercepted operations.
我们看Proxy现在支持已经很成熟了
<script>
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p);
</script>
当然我们也可以使用set和get来validate我们可以在set里面做一些判断
<script>
let object = {
a: 1,
b: 2
}
let handlers = []
function reactive(obj) {
return new Proxy(obj, {
get(obj, prop) {
console.log(obj, prop)
return obj[prop]
},
set(obj, prop, val) {
console.log(obj, prop, val)
obj[prop] = val
for (let handler of handlers)
handler()
return obj[prop]
}
})
}
function effect(handler) {
handler()
handlers.push(handler)
}
let dummy;
let proxy = reactive(object)
effect(() => dummy = proxy.a)
console.log(dummy)
proxy.a = 111
console.log(dummy)
</script>
最终我们来实现双向数据绑定
<input id="test">
<script>
let object = {
a: {x:1},
b: 2
}
let handlers = new Map()
let usedReactivities = []
let reactivites = new Map()
function reactive(obj) {
if(reactivites.has(obj)){
return reactivites.get(obj)
}
return new Proxy(obj, {
get(obj, prop) {
console.log(obj, prop)
usedReactivities.push([obj,prop])
if(typeof obj[prop] === 'object'){
return reactive(obj[prop])
}
return obj[prop]
},
set(obj, prop, val) {
obj[prop] = val
console.log(handlers)
console.log(obj, prop, val)
if( handlers.get(obj)){
if( handlers.get(obj).get(prop)){
for(let handler of handlers.get(obj).get(prop)){
handler()
}
}
}
return obj[prop]
}
})
reactivites.set(obj, proxy)
reactivites.set(proxy, proxy)
return proxy
}
let proxy = reactive(object)
function effective(handler) {
usedReactivities=[]
handler()
console.log(usedReactivities)
for (let usedReactivity of usedReactivities){
let [obj, prop] = usedReactivity
console.log([obj, prop])
if(!handlers.has(obj)){
handlers.set(obj, new Map())
}
if(!handlers.get(obj).has(prop)){
handlers.get(obj).set(prop, [])
}
handlers.get(obj).get(prop).push(handler)
}
}
let p = reactive({r:100})
effective(()=>{
document.getElementById("test").value= p.r
})
document.getElementById("test").addEventListener("input", e=>{
p.r = e.target.value
})
</script>