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() //收回代理

 

posted @ 2021-08-16 13:27  卷叶小树  阅读(102)  评论(0编辑  收藏  举报