Proxy
1.语法
let proxy = new Proxy(target,handler)
let star = { name:"尼古拉斯凯奇", age:40, job:"actor", phone:"18900012345" } let proxy = new Proxy(star,{ get(target,key,receiver){ // target 代表start,key代表属性名称,receiver代表proxy,this代表Proxy的第二个参数 if(key === 'phone'){ throw new Error('不能访问电话') } return target[key] }, set(target, key, value, receiver) { if(key === 'phone'){ throw new Error('不能修改电话') } target[key] = value }
})
2.代理拦截方法 -get
2.1.对数据做校验
2.2.对数组,字符串索引值做处理
2.3.链式调用
let str = 'hello' let ickt = function (val,tools){ return new Proxy({},{ fns: [], get(target,key,proxy){ if(key === 'get'){ return this.fns.reduce((result,fn)=>(tools || result)[fn](result),val) } this.fns.push(key) return proxy } })
} const tools = { toUpperCase:val => val.toUpperCase(), repeat:val => val.repeat(2), trim:val => val.trim(), reverse:val => val.split('').reverse().join('')
} console.log(ickt(str,tools).trim.toUpperCase.repeat.reverse.get)
2.4.模拟虚拟dom创建
let React = new Proxy({},{ get(obj,name){ return function (attrs,...children){ // 创建容器元素 let dom = document.createElement(name); // 遍历属性 attrs && Object.keys(attrs).forEach(key => dom.setAttribute(key,attrs[key])) // 遍历子元素 children.forEach(item => { if(typeof item === 'string'){ dom.appendChild(document.createTextNode(item)) } else { dom.appendChild(item) } }) return dom } }
}) const a = React.div( {id:'app'}, React.img({src:'./demo.png',alt:'demo'}), React.p(null,'喵喵')
) document.getElementById('container').appendChild(a)
2.5.configurable、writeable
不传递操作对象,此时代理对象和原对象的行为是一致的
let obj = { msg:'hello' } Object.defineProperties(obj,{ color:{ value:'red', writable:false, enumerable:true, configurable:true }, num:{ value:20, writable:true, enumerable:true, configurable:false } }) let proxy = new Proxy(obj,{})
3.代理拦截方法 -set
3.1.数据校验
3.2.私有属性,以_开头的属性,保护属性
3.3.改变运算符的默认行为
4.其它方法
has() in操作-调用
deleteProperty() 删除属性-调用
ownKeys() getOwnPropertyNames()、getOwnPropertySymbols()、Object.keys()-调用
getOwnPropertyDescriptor()
defineProperty()
preventExtensions()
isExtensible()
getPrototypeOf()
setPrototypeOf()
apply() 拦截Proxy实例
construct() proxy作为构造函数调用-执行
5.isExtensible,seal,freeze区别
不可拓展、密封、冻结
查看--isExtensible() isSealed() isFreezen()
let demo = { color:'red', num:10 } // 添加熟悉 demo.msg = 'hello' // 修改属性 demo.color = 'green' // 删除属性 delete demo.num // 特性添加 Object.defineProperties(demo,'title',{value:'ickt'}) Object.preventExtensions(demo) //不能添加,可删除、修改,特性添加报错 Object.seal(demo) //不能添加、删除,可修改,特性添加报错 Object.freeze(demo) //不能添加、删除、修改,特性添加报错
6.代理对象和类
一些原生方法,只能通过正确的this才能获取数据,此时就无法使用proxy做代理了
因为this的指向问题
比如正则
let map = new Map() // key可以是任何数据类型的 class Demo{ constructor(color) { this._color = color } get color(){ // 通过demo和proxy调用color,this指向不同 console.log(this) return this.color } } let demo = new Demo('red') let proxy = new Proxy(demo,{}) console.log(demo) console.log(proxy)
7.Proxy.revocable()方法可以返回一个可取消的代理对象
其中revoke属性可以取消proxy代理实例
应用场景:收回代理权
let {proxy,recvoke} = Proxy.revocable(obj,{}) console.log(proxy.color) recvoke() //收回代理