美文网首页
Proxy Reflect

Proxy Reflect

作者: 简单tao的简单 | 来源:发表于2020-02-24 15:22 被阅读0次

Proxy

Proxy 用于修改某些操作的默认行为,Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

        //如果handler没有设置任何拦截,那就等同于直接通向原对象
        var target = {}
        var handler = {}
        var proxy = new Proxy(target,handler)
        proxy.a = 'b';

        console.log(proxy) //Proxy {a: "b"}
        console.log(target) //{a: "b"}

        //由于拦截函数总是返回35,所以访问任何属性都得到35
        var target = {}
        var handler = {
            get:function(target,property){
                return 35;
            }
        }
        var proxy1 = new Proxy(target,handler)

        console.log(proxy1.name) //35
        console.log(proxy1.city) //35

Reflect

Reflect是ES6为了操作对象而提供的新API,之前都用Object的方法操作对象,现在不用Object的方法了,用Reflect的方法。Reflect的方法跟Proxy方法名一样,一一对应。Reflect的方法也跟Object的同名方法功能一样,只不过Reflect的方法比Object的同名方法返回值更合理一些

设计Reflect的目的如下:
  1. 将Object对象的方法(比如Object.defineProperty),放到Reflect对象上,让Object专注于数据
  2. 某些Object方法的返回结果不合理,比如Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误。而Reflect.defineProperty(obj, name, desc)则会返回false
// 老写法
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}

// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}
  1. 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为
// 老写法
'assign' in Object // true

// 新写法
Reflect.has(Object, 'assign') // true
  1. Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target,name, value, receiver);
    if (success) {
      log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

上面代码中,Proxy方法拦截target对象的属性赋值行为。它采用Reflect.set方法将值赋值给对象的属性,然后再部署额外的功能。

Reflect用法
        var target = {}
        var success = Reflect.set(target,'name', 'abc');
        console.log(success) //true
        console.log(target) //{name: "abc"}
自我理解
  • Proxy就是在操作对象的时候对相关方法做一些拦截,然后再做相应处理
  • Reflect就是专门操作对象用的
  • Proxy和Reflect配合使用,在操作对象时Proxy拦截后,用Reflect操作对象,进行二次包装
const data = {
    name: 'zhangsan',
    age: 20,
}
//const data = ['a', 'b', 'c']

const proxyData = new Proxy(data, {  //proxyData 就是 data 对象的 proxy 代理
    get(target, key, receiver) {
        // 只处理本身(非原型的)属性
        const ownKeys = Reflect.ownKeys(target)
        if (ownKeys.includes(key)) {
            console.log('get', key) // 监听
        }

        const result = Reflect.get(target, key, receiver)
        return result // 返回结果
    },
    set(target, key, val, receiver) {
        // 重复的数据,不处理
        if (val === target[key]) {
            return true
        }

        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        // console.log('result', result) // true
        return result // 是否设置成功
    },
    deleteProperty(target, key) {
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        // console.log('result', result) // true
        return result // 是否删除成功
    }
})
console.log(proxyData.name) //"zhangsan"
//访问 proxyData 对象的属性 name 就回被 Proxy 的get方法拦截,通过Reflect.get(target, key, receiver)获取属性值,返回‘zhangsan’
用 Proxy Reflect 实现响应式
// 创建响应式
function reactive(target = {}) {
    if (typeof target !== 'object' || target == null) {
        // 不是对象或数组,则返回
        return target
    }

    // 代理配置
    const proxyConf = {
        get(target, key, receiver) {
            // 只处理本身(非原型的)属性
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('get', key) // 监听
            }
    
            const result = Reflect.get(target, key, receiver)
        
            // 深度监听
            // 性能如何提升的?
            return reactive(result)
        },
        set(target, key, val, receiver) {
            // 重复的数据,不处理
            if (val === target[key]) {
                return true
            }
    
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('已有的 key', key)
            } else {
                console.log('新增的 key', key)
            }

            const result = Reflect.set(target, key, val, receiver)
            console.log('set', key, val)
            // console.log('result', result) // true
            return result // 是否设置成功
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key)
            console.log('delete property', key)
            // console.log('result', result) // true
            return result // 是否删除成功
        }
    }

    // 生成代理对象
    const observed = new Proxy(target, proxyConf)
    return observed
}

// 测试数据
const data = {
    name: 'zhangsan',
    age: 20,
    info: {
        city: 'beijing',
        a: {
            b: {
                c: {
                    d: {
                        e: 100
                    }
                }
            }
        }
    }
}
const proxyData = reactive(data)

相对于Object.defineProperty的

优点

  • 深度监听,不需要一次性递归到底,用到那一次,递归到哪一层
  • 可以监听新增属性/删除属性
  • 可以监听原生数组,不需要特殊处理

缺点

  • Proxy存在浏览器兼容性问题,且不能polyfill

相关文章

网友评论

      本文标题:Proxy Reflect

      本文链接:https://www.haomeiwen.com/subject/nhcvqhtx.html