Proxy是ES6中提供的新的API,可以用来定义对象各种基本操作的自定义行为 (在文档中被称为traps,我觉得可以理解为一个针对对象各种行为的钩子),拿它可以做很多有意思的事情,在我们需要对一些对象的行为进行控制 ...
Proxy是什么首先,我们要清楚, 可以理解为,有一个很火的明星,开通了一个微博账号,这个账号非常活跃,回复粉丝、到处点赞之类的,但可能并不是真的由本人在维护的。 而是在背后有一个其他人 or 团队来运营,我们就可以称他们为代理人,因为他们发表的微博就代表了明星本人的意思。 P.S. 强行举例子,因为本人不追星,只是猜测可能会有这样的运营团队 这个代入到 JavaScript中的ProxyProxy是ES6中提供的新的API,可以用来定义对象各种基本操作的自定义行为 (在文档中被称为traps,我觉得可以理解为一个针对对象各种行为的钩子),拿它可以做很多有意思的事情,在我们需要对一些对象的行为进行控制时将变得非常有效。 Proxy的语法创建一个
let target = {} let handlers = {} // do nothing let proxy = new Proxy(target, handlers) proxy.a = 123 console.log(target.a) // 123 在第二个参数为空对象的情况下,基本可以理解为是对第一个参数做的一次浅拷贝 Traps(各种行为的代理)就像上边的示例代码一样,如果没有定义对应的 当我们写了某个 最常用的两个 早年 let obj = { _age: 18, get age () { return `I'm ${this._age} years old` }, set age (val) { this._age = Number(val) } } console.log(obj.age) // I'm 18 years old obj.age = 19 console.log(obj.age) // I'm 19 years old 就像这段代码描述的一样,我们设置了一个属性 然后我们可以直接调用 这么做有几个缺点:
let target = { age: 18, name: 'Niko Bellic' } let handlers = { get (target, property) { return `${property}: ${target[property]}` }, set (target, property, value) { target[property] = value } } let proxy = new Proxy(target, handlers) proxy.age = 19 console.log(target.age, proxy.age) // 19, age : 19 console.log(target.name, proxy.name) // Niko Bellic, name: Niko Bellic 我们通过创建 而且我们无需额外的用一个 拿Proxy来做些什么因为在使用了 在下边列出了几个简单的适用场景。 解决对象属性为undefined的问题在一些层级比较深的对象属性获取中,如何处理 (() => { let target = {} let handlers = { get: (target, property) => { target[property] = (property in target) ? target[property] : {} if (typeof target[property] === 'object') { return new Proxy(target[property], handlers) } return target[property] } } let proxy = new Proxy(target, handlers) console.log('z' in proxy.x.y) // false (其实这一步已经针对`target`创建了一个x.y的属性) proxy.x.y.z = 'hello' console.log('z' in proxy.x.y) // true console.log(target.x.y.z) // hello })() 我们代理了 这样就能够保证我们的取值操作一定不会抛出 普通函数与构造函数的兼容处理如果我们提供了一个 class Test { constructor (a, b) { console.log('constructor', a, b) } } // Test(1, 2) // throw an error let proxyClass = new Proxy(Test, { apply (target, thisArg, argumentsList) { // 如果想要禁止使用非new的方式来调用函数,直接抛出异常即可 // throw new Error(`Function ${target.name} cannot be invoked without 'new'`) return new (target.bind(thisArg, ...argumentsList))() } }) proxyClass(1, 2) // constructor 1 2 我们使用了 以及如果我们想要对函数进行限制,禁止使用 function add (a, b) { return a + b } let proxy = new Proxy(add, { construct (target, argumentsList, newTarget) { throw new Error(`Function ${target.name} cannot be invoked with 'new'`) } }) proxy(1, 2) // 3 new proxy(1, 2) // throw an error 用Proxy来包装fetch在前端发送请求,我们现在经常用到的应该就是 let handlers = { get (target, property) { if (!target.init) { // 初始化对象 ['GET', 'POST'].forEach(method => { target[method] = (url, params = {}) => { return fetch(url, { headers: { 'content-type': 'application/json' }, mode: 'cors', credentials: 'same-origin', method, ...params }).then(response => response.json()) } }) } return target[property] } } let API = new Proxy({}, handlers) await API.GET('XXX') await API.POST('XXX', { body: JSON.stringify({name: 1}) }) 对 实现一个简易的断言工具写过测试的各位童鞋,应该都会知道断言这个东西 let assert = new Proxy({}, { set (target, message, value) { if (!value) console.error(message) } }) assert['Isn\'t true'] = false // Error: Isn't true assert['Less than 18'] = 18 >= 19 // Error: Less than 18 统计函数调用次数在做服务端时,我们可以用 function orginFunction () {} let proxyFunction = new Proxy(orginFunction, { apply (target, thisArg. argumentsList) { log(XXX) return target.apply(thisArg, argumentsList) } }) 全部的traps这里列出了
更多编程相关知识,请访问:编程学习网站!! 以上就是详解JavaScript中的Proxy(代理)的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |