zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    32-3题:LeetCode103. Binary Tree Zigzag Level Order Traversal锯齿形层次遍历/之字形打印二叉树
    32-1题:不分行从上到下打印二叉树/BFS/deque/queue
    第31题:LeetCode946. Validate Stack Sequences验证栈的序列
    第30题:LeetCode155. Min Stack最小栈
    第29题:LeetCode54:Spiral Matrix螺旋矩阵
    第28题:leetcode101:Symmetric Tree对称的二叉树
    第27题:Leetcode226: Invert Binary Tree反转二叉树
    第26题:LeetCode572:Subtree of Another Tree另一个树的子树
    第25题:合并两个排序的链表
    第24题:反转链表
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13821562.html
Copyright © 2011-2022 走看看