• Proxy代理


    Proxy对象

    在一个系统中,总要存储一些数据,对于这些数据,可能有一些是希望我们访问的,但是总有一些是中重要的,不希望我们访问的,希望保护起来,因此ES6新增了代理,在目标对象前架设个“拦截“层,外界对该对象的访问必须通过这层拦截,我们可以对外界的访问进行过滤和改写。

    注意:Proxy修改了某些操作的默认行为,等同于在语言层做出修改,所以也属于”元编程“,即对语言进行编程。

    语法: let proxy = new Proxy(target,handler)
    
    target 表示被代理的对象
    
    handler 表示操作被代理的对象
    

    注意:[[]] 为引擎内部属性或方法,外部不能获取

    let star = {
        name: '尼古拉斯赵四',
        girlFriend: '赵丽颖',
        age: 40
    }
    // 代理对象
    let proxy = new Proxy(star, {
        // 取值方法
        get(target, key, receiver) {
            // 如果是重要的数据,不要访问
            if (key === 'girlFriend') {
                throw new Error('不能访问girlFriend')
            }
            if (key === 'age') {
                return 0
            }
            // target 代表 star, key 代表属性名称, receiver代表proxy, this代表Proxy的第二个参数对象
            // console.log('get', receiver === this, 11, receiver === proxy, this.num)
            return target[key]
        },
        set(target, key, value, receiver) {
            // 如果是重要的数据,不要修改
            if (key === 'girlFriend') {
                throw new Error('不能修改girlfriend')
            }
            // console.log('set', ...args, this)
            // console.log(value)
            target[key] = value;
        },
        num: 10
    })
    // // 修改数据
    // proxy.name = '亚洲舞王'
    // // 获取数据
    // console.log(proxy.name)
    // 修改重要数据
    // proxy.girlFriend = '孙俪'
    // console.log(proxy.girlFriend, star.girlFriend)
    // ++star.age;
    // proxy.age;
    console.log(++proxy.age)

    拦截方法

    get(target,key,proxy) 拦截对象属性的读取

    //get(target,key,proxy) 拦截对象属性的读取
        // 1 对数据做校验
        // 2 数组或者字符串的索引值做处理(负索引值)
        // 3 方法链式调用
        // 4 模拟虚拟DOM创建
        // 5 configurable, writable
    
    // 负索引值
    // let arr = [1, 2, 3, 4, 5];
    // let proxy =  new Proxy(arr, {
    //     // 取值方法
    //     get(target, key) {
    //         // 如果是负索引值
    //         if (key < 0) {
    //             key = key % target.length + target.length;
    //         }
    //         return target[key]
    //     }
    // })
    // console.log(proxy[1])
    // console.log(proxy[-1])
    
    // 链式调用
    // let str = 'hello   ';
    // console.log(str.trim().toUpperCase())
    // console.log(str.trim.toUpperCase)
    // 定义一个方法,包装字符串
    // let ickt = function(val) {
    //     // 返回一个代理对象
    //     return new Proxy({}, {
    //         fns: [],
    //         // 取值方法
    //         get(target, key, proxy) {
    //             // 如果key是get,返回结果
    //             if (key === 'get') {
    //                 // console.log(this.fns)
    //                 // 执行对val的处理,并返回结果
    //                 // return this.fns.reduce((result, fn) => {
    //                 //     return result[fn](result)
    //                 // }, val)
    //                 return this.fns.reduce((result, fn) => result[fn](result), val)
    //             }
    //             // 存储这些操作方法
    //             this.fns.push(key)
    //             // 为了链式调用,每次要返回receiver
    //             return proxy
    //         }
    //     })
    // }
    // 使用方法,省略()
    // console.log(ickt(str).trim.toUpperCase.get)
    // let ickt = function(val, tools) {
    //     // 返回一个代理对象
    //     return new Proxy({}, {
    //         fns: [],
    //         // 取值方法
    //         get(target, key, proxy) {
    //             // 如果key是get,返回结果
    //             if (key === 'get') {
    //                 // console.log(this.fns)
    //                 // 执行对val的处理,并返回结果
    //                 // return this.fns.reduce((result, fn) => {
    //                 //     return result[fn](result)
    //                 // }, val)
    //                 return this.fns.reduce((result, fn) => (tools || result)[fn](result), val)
    //             }
    //             // 存储这些操作方法
    //             this.fns.push(key)
    //             // 为了链式调用,每次要返回receiver
    //             return proxy
    //         }
    //     })
    // }
    // // 工具方法
    // let 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.repeat.reverse.toUpperCase.get)
    
    // react jsx
    // <div id="app">
    //     <img src="./demo.png" alt="demo">
    //     <p>爱创课堂</p>
    // </div>
    // react.createElement(
    //     'div', 
    //     { id: 'app' },
    //     React.createElement('img', { src: './demo.png', alt: 'demo' }),
    //     React.createElement('p', null, '爱创课堂')
    // )
    // 创建React库
    // 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;
    //         }
    //     }
    // })
    // // // 模拟React创建DOM元素
    // let result = React.div(
    //     { id: 'app' },
    //     React.img({ src: './demo.png', alt: 'demo' }),
    //     React.p(null, '爱创课堂')
    // )
    // // console.log(result)
    // // 上树
    // document.body.appendChild(result);
    
    // configurable, writable
    // 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, {})
    // // 不传递操作方法,此时代理对象与原对象的行为是一致的
    // console.log(proxy.msg)
    // proxy.msg = 'ickt';
    // // console.log(proxy.msg)
    // console.log(obj)
    // console.log(proxy.color)
    // proxy.color = 'green';
    // console.log(proxy.color)
    // Object.defineProperty(obj, 'num', {
    //     value: 30,
    //     writable: true,
    //     enumerable: true,
    //     configurable: true
    // })
    // Object.defineProperty(proxy, 'num', {
    //     value: 30,
    //     writable: true,
    //     enumerable: true,
    //     configurable: true
    // })
    // console.log(obj)
    
    set(target,key,value,proxy) 拦截对象属性的设置
    
    has(target,key) 拦截propKey in proxy 的操作, 返回布尔值
    
    deleteProperty(target,key) 拦截delete proxy[key] 操作,返回布尔值
    
    ownKeys(target) 拦截	
    Object.getOwnPropertyNames,Object.getOwnPropertySymbols,Object.keys,返回值是个数组
    
    getOwnPropertyDescriptor(target,key) 拦截 Object.getOwnPropertyDescriptor操作,返回属性值的描述对象
    
    defineProperty(target,key,descripor) 拦截Object.defineProperty Object.defineProperties 操作。
    
    preventExtensions(target) 拦截 Object.preventExtensions(不可拓展) ,返回布尔值
    
    idExtensible(target) 拦截Object.idExtensible , 返回布尔值
    
    Object.getPrototypeOf(target)  拦截Object.getPrototypeOf(target)  ,返回对象
    
    Object.setPrototypeOf(target,proto)  拦截Object.setPrototypeOf(target,proto) ,返回布尔值
    
    Object.setPrototypeOf(target)  拦截Proxy实例 并将其作为函数调用操作
    
    Object.construct(target,args)  拦截Proxy实例 作为构造函数调用的操作
    
    // 定义对象
    // let obj = {
    //     color: 'red',
    //     num: 10
    // }
    let obj = function() {
        console.log('obj fn')
    }
    // 代理
    let proxy = new Proxy(obj, {
        // has(target, key) 			拦截propKey in proxy 的操作,返回 个布尔值。
        // has() {
        //     console.log(arguments)
        // }
        // deleteProperty(target, key) 		拦截 delete proxy[key]的操作,返回 个布尔值。
        // deleteProperty() {
        //     console.log(arguments)
        // }
        // ownKeys(target) 			拦截Object.getOwnPropertyNames,Object.getOwnPropertySymbols,					Object.keys,返回 个数组。
        // ownKeys() {
        //     console.log(arguments)
        //     return []
        // }
        // getOwnPropertyDescriptor(target, key) 拦截Object.getOwnPropertyDescriptor操作,返回属性的描述对象。
        // defineProperty(target, key, descripor) 	拦截Object.defineProperty、 Object defineProperties操作
        // preventExtensions(target) 		拦截Object.preventExtensions (不可拓展),返回布尔值
        // isExtensible(target) 		拦截Object.isExtensible, 返回布尔值。
        // getPrototypeOf(target) 		拦截Object.getPrototypeOf,返回对象。
        // setPrototypeOf(target, proto) 	拦截Object.setPrototypeOf, 返回一个布尔值。 
        // apply(target, object, args) 		拦截Proxy实例,并将其作为函数调用的操作 
        apply() {
            console.log(arguments)
        },
        // construct( target, args) 
        construct() {
            console.log('construct', arguments)
            return {}
        }
    })
    // console.log('color' in proxy)
    // delete proxy.color
    // console.log(Object.getOwnPropertyNames(proxy))
    
    // 执行方法
    // proxy(1, 2, 3)
    // proxy.call({ color:'red' }, 1, 2, 3)
    // 作为构造函数
    new proxy(1, 2, 3)
    

    电脑刺绣绣花厂 http://www.szhdn.com 广州品牌设计公司https://www.houdianzi.com

    Proxy要点

    1、当操作代理对象参数是空对象的时候,对代理对象的操作将直接映射给被代理对象(无拦截)。

    let obj = {}
    // 代理
    let proxy = new Proxy(obj, {})
    // proxy与obj行为是一致的
    proxy.color = 'red'
    console.log(obj)//{color:"red"}
    

    2、Proxy对目标对象的代理,是不透明的代理,因此在无拦截的情况下,也无法保证与目标对象的行为一直。原因是在Proxy代理过程中,Proxy代理对象内部this始终指向Proxy代理对象。

    // let obj = {
    //     num: 10,
    //     demo() {
    //         console.log(this)
    //     }
    // }
    // 代理对象, 无拦截
    // let proxy = new Proxy(obj, {})
    // this指向 obj
    // obj.demo()  //obj
    // proxy.demo() //proxy 代理对象
    
    // map对象: 属性名称可以是任何数据类型。
    // let map = new Map();
    // // let map = {};
    // // 类
    // class Demo {
    //     constructor(color) {
    //         // this._color = color;
    //         // map[this] = color;
    //         map.set(this, color);
    //     }
    //     // 特性方法
    //     get color() {
    //         // 通过demo和proxy调用color属性,this指向不同。
    //         console.log(this, map)
    //         // return this._color;
    //         // return map[this];
    //         return map.get(this);
    //     }
    // }
    // // 实例化
    // let demo = new Demo('red');
    // // 代理对象, 无拦截
    // let proxy = new Proxy(demo, {})
    // // this指向 obj
    // console.log(demo.color);
    // console.log(proxy.color);
    

    所以代理一些实例化对象的时候会存在this问题。 3、一些源生方法,只能通过正确的this才能获取数据,此时就无法使用Proxy做代理。

    // 3 一些源生方法,只能通过正确的this才能获取数据,此时就无法使用proxy做代理了
    // let r = /a/;
    // let proxy = new Proxy(r, {});
    // // 使用
    // console.log(r.test('a'))
    // console.log(proxy.test('a'))
    

    4、Proxy.revocable方法可以返回一个可取消的代理对象。 其中revoke属性可以取消proxy代理实例。 应用场景“目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问

    // 4 取消代理
    let obj = {
        color: 'red'
    }
    let { proxy, revoke } = Proxy.revocable(obj, {});
    // console.log(ickt)
    // 代理
    console.log(proxy.color)
    // 收回代理权
    revoke();
    // 代理失效
    console.log(proxy.color)
  • 相关阅读:
    vim复制
    嵌入式Linux学习(二)
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1025 数的划分
    (Java实现)洛谷 P1093 奖学金
    (Java实现)洛谷 P1093 奖学金
    Java实现 洛谷 P1064 金明的预算方案
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13821562.html
Copyright © 2020-2023  润新知