当前位置: 首页>数据库>正文

二、响应式框架基本原理(Proxy部分)

根据上一节,我们知道了使用defineProperty来监听数据的变化。大概知道响应式的基本原理。这一节我们可以通过另外一种方式来做,既使用ES Next的新特性-----Proxy做数据代理。去实现数据监听。

Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

语法:
const p = new Proxy(target, handler)
参数:

target ( 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。)

handler ( 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。)

handler

handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
捕捉器等更多详细 请查看链接 Proxy详细说明

首先我们先尝试使用Proxy来完成上一节代码的重构。

let data = {
    name: 'fzs',
    info: {
        age: 18,
        driving: 2,
        familyTies: {
            maritalStatus: '已婚'
        },
        hobby: ['乒乓球', '游泳']
    },
}
const observe = data => {
    if (!data || Object.prototype.toString.call(data) !== '[object Object]') {
        return
    }
    Object.keys(data).forEach(key => {
        let currentValue = data[key]
        // 事实上, Proxy也可以对函数类型进行代理。这里只对承载数据类型的Object进行处理。大家了解即可
        if (typeof currentValue === 'object') {
            // 递归处理对象类型,通过proxy代理
            observe(currentValue)
            data[key] = new Proxy(currentValue, {
                set: (target, property, value, reciver) => {
                    // setter中执行各种操作,存储等
                    console.log('这是赋值操作')
                    if (value === currentValue) {
                        console.log('不需要重新赋值处理')
                        return true
                    }
                    if (property !== 'length') {
                        console.log('数组只需要执行一次赋值操作,因为push方法会引起length的变化,触发两次set操作,我们只需要保留一次即可')
                        // 这里进行我们数组的赋值拦截的其他操作
                    }
                    return Reflect.set(target, property, value) //todo 这是赋值操作
                },
            })
        } else {
            Object.defineProperty(data, key, {
                enumerable: false,
                configurable: false,
                get() {
                    console.log(`getting ${key} value now, getting value is:`, currentValue)
                    return currentValue
                },
                set(newValue) {
                    currentValue = newValue
                    console.log(`setting ${key} value now, setting value is`, currentValue)
                }
            })
        }
    })
}
observe(data)
// 对数组进行如下操作
if (data.info.hobby) {
    data.info.hobby.push('打篮球')
}

观察输出我们发现程序已经监听到了深层数据的变动。

简单总结一下:

1.对于数据键值类型为基本类型的情况,我们可以继续使用Object.defineProperty
2.对于键值为对象类型的情况,我们可以继续递归调用observe方法,并通过Proxy返回的新对象对data[key]重新赋值,这个新值的gettersetter已经被添加了代理。

了解了Proxy实现之后,我们对使用Proxy实现数据代理和使用Object.defineProperty实现数据拦截进行对比,可以得出一下 结论

  • Object.defineProperty不能监听数组的变化,需要对数组方法进行重写。
  • Object.defineProperty必须遍历对象的每个属性,且需要对嵌套结构进行深层遍历。
  • Proxy 的代理是针对整个对象的,而不是针对 对象 的某个属性。因此不像Object.defineProperty必须遍历对象的每个属性,Proxy只需要做一层代理就可以监听同级结构下的所有属性变化。当然对于深层结构,递归还是需要进行的。
  • Proxy支持代理数组的变化。
  • Proxy 的第二个参数除了可以使用 set 和 get, 还可以使用13种拦截方法,比Object.defineProperty更强大。 Proxy详细说明
  • 使用Proxy时,性能将会被底层持续优化;而使用Object.defineProperty时,性能已经不再是优化重点。

https://www.xamrdz.com/database/6rn1995715.html

相关文章: