JavaScript中的ES6 Proxy的具体使用(3)

// 模拟页面的复选框列表 const hobbyMap = new Map() .set(1, '小说') .set(2, '动画') .set(3, '电影') .set(4, '游戏') const user = { id: 1, // 保存兴趣 id 的列表 hobbySet: new Set(), // 发送到后台的兴趣 id 拼接后的字符串,以都好进行分割 hobby: '', } function onClick(id) { user.hobbySet.has(id) ? user.hobbySet.delete(id) : user.hobbySet.add(id) } // 模拟两次点击 onClick(1) onClick(2) console.log(user.hobby) // ''

下面使用 Proxy 来完成 hobbySet 属性改变后 hobby 自动更新的操作

/** * 深度监听指定对象属性的变化 * 注:指定对象不能是原始类型,即不可变类型,而且对象本身的引用不能改变,最好使用 const 进行声明 * @param object 需要监视的对象 * @param callback 当代理对象发生改变时的回调函数,回调函数有三个参数,分别是对象,修改的 key,修改的 v * @returns 返回源对象的一个代理 */ function watchObject(object, callback) { const handler = { get(_, k) { try { // 注意: 这里很关键,它为对象的字段也添加了代理 return new Proxy(v, Reflect.get(_, k)) } catch (err) { return Reflect.get(_, k) } }, set(_, k, v) { callback(_, k, v) return Reflect.set(_, k, v) }, } return new Proxy(object, handler) } // 模拟页面的复选框列表 const hobbyMap = new Map() .set(1, '小说') .set(2, '动画') .set(3, '电影') .set(4, '游戏') const user = { id: 1, // 保存兴趣 id 的列表 hobbySet: new Set(), // 发送到后台的兴趣 id 拼接后的字符串,以都好进行分割 hobby: '', } const proxy = watchObject(user, (_, k, v) => { if (k === 'hobbySet') { _.hobby = [..._.hobbySet].join(',') } }) function onClick(id) { proxy.hobbySet = proxy.hobbySet.has(id) ? proxy.hobbySet.delete(id) : proxy.hobbySet.add(id) } // 模拟两次点击 onClick(1) onClick(2) // 现在,user.hobby 的值将会自动更新 console.log(user.hobby) // 1,2

当然,这里实现的 watchObject 函数还非常非常非常简陋,如果有需要可以进行更深度/强大的监听,可以尝试自行实现一下啦!

缺点

说完了这些 Proxy 的使用场景,下面稍微来说一下它的缺点

运行环境必须要 ES6 支持

这是一个不大不小的问题,现代的浏览器基本上都支持 ES6,但如果泥萌公司技术栈非常老旧的话(例如支持 IE6),还是安心吃土吧 #笑 #这种公司不离职等着老死

不能直接代理一些需要 this 的对象

这个问题就比较麻烦了,任何需要 this 的对象,代理之后的行为可能会发生变化。例如 Set 对象

const proxy = new Proxy(new Set([]), {}) proxy.add(1) // Method Set.prototype.add called on incompatible receiver [object Object]

是不是很奇怪,解决方案是把所有的 get 操作属性值为 function 的函数都手动绑定 this

const proxy = new Proxy(new Set([]), { get(_, k) { const v = Reflect.get(_, k) // 遇到 Function 都手动绑定一下 this if (v instanceof Function) { return v.bind(_) } return v }, }) proxy.add(1)

总结

Proxy 是个很强大的特性,能够让我们实现一些曾经难以实现的功能(所以这就是你不支持 ES5 的理由?#打),就连 Vue3+ 都开始使用 Proxy 实现了,你还有什么理由在乎上古时期的 IE 而不用呢?(v^_^)v

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/b7daa3aa1b37b9ceded6ba12becc9d66.html