本章总结了代理与反射的内容
代理
代理为开发者提供了拦截并向基本操作嵌入额外行为的能力
基础声明
有如下几个注意要点
对proxy的修改,假如没有进行拦截,原对象也会进行修改
经proxy包装的对象与原对象进行比较,并非严格相等
不能对Proxy对象使用instanceof操作服
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const testTarget = { info :1 }const handler = {}const proxy = new Proxy (testTarget, handler) proxy.info = 2 console .log (testTarget.info )console .log (testTarget === handler)console .log (testTarget instanceof Proxy )
捕获器及API
get-trap参数
property, receiver ``` 分别代表访问对象,访问属性,proxy参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ```javascript const testTarget = { info:1 } const handler = { get(target, property, receiver) { console.log(target, property, receiver) return 1 } } const proxy = new Proxy(testTarget, handler) console.log(proxy.aaa) // 1
trap invariant
如果对象存在不可写且不可配置的属性,会抛出异常TypeError
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const testTarget = { }Object .defineProperty ( testTarget, "info" , { writable : false , configurable : false , value :"hi" } )let handler = { get (target, property, receiver ) { return 123 } }const proxy = new Proxy (testTarget, handler)console .log (proxy.info )
可撤销代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const testTarget = { }Object .defineProperty ( testTarget, "info" , { writable : false , configurable : false , value :"hi" } )let handler = { get (target, property, receiver ) { return 123 } }const {proxy, revoke} = Proxy .revocable (testTarget, handler)console .log (proxy.info )revoke ()console .log (proxy.info )
可能出现的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const testTarget = { testFunc ( ) { console .log (this === testTarget) } }let handler = { get (target, property, receiver ) { console .log (this ===target) return Reflect .get (...arguments ) } }const proxy = new Proxy (testTarget,handler) proxy.testFunc () testTarget.testFunc ()
1 2 3 4 const target = new Date ();const proxy = new Proxy (target, {});console .log (proxy instanceof Date ); proxy.getDate ();
to fix:
1 2 3 4 5 const target = new Date ();const Pro = new Proxy (Date , {});const proxy = new Pro ()console .log (proxy instanceof Date ); proxy.getDate ();
代理捕获器
get
参数:target
、property
、receiver
拦截操作:
proxy[property]
proxy.property
Reflect.get(target, property, receiver)
set
参数:target, property, value, receiver
拦截:
proxy[property] = val
proxy.property = val
Object.create(proxy)[property] = value
Reflect.set(obj,property,val)
代理的用途
一些面试题
1. Reflect对象和Object对象的区别?
1 2 3 Proxy 定义了拦截的行为,Reflect 集合了部分Object 的操作,未来的操作将部署在Reflect 上Proxy 的函数负责的是:拦截并定义拦截时具体的操作;Reflect 的静态函数负责的是:最终执行对象的操作,因此保持一致
2. vue3如何实现双向绑定?与vue2有何区别?
关于绑定的实现
1 2 3 vue3通过proxy实现双向绑定,可以监听到内部数据变化 vue2不可以,需要使用$set 更新视图 vue2使用Object .defineProperty监听变化
下面是简单的一个数据绑定的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <html > <title > testTitle</title > <body > <h1 id ="tree-val1" > 123</h1 > </body > <script > let handler = { set (obj, property, val ) { console .log (obj,property) Reflect .set (...arguments ) const ele = document .getElementById ("tree-" +property) if (ele!==null &&ele!==undefined ) { ele.innerHTML = val } } } let obj = { val1 : "123" } let proxy = new Proxy (obj, handler) setTimeout (()=> { proxy.val1 = "456" console .log (proxy.val1 ) },2000 ) </script > </html >
1 Object .defineProperties ()
vue2实现
vue3实现
3. getter和setter与proxy的区别
1 2 3 4 5 6 1. Proxy 是对整个对象的代理,而 Object .defineProperty 只能代理某个属性。2. 对象上新增属性,Proxy 可以监听到,Object .defineProperty 不能。3. 数组新增修改,Proxy 可以监听到,Object .defineProperty 不能。4. 若对象内部属性要全部递归代理,Proxy 可以只在调用的时候递归,而 Object .definePropery 需要一次完成所有递归,性能比 Proxy 差。5. Proxy 不兼容 IE,Object .defineProperty 不兼容 IE8 及以下6. Proxy 使用上比 Object .defineProperty 方便多。