数据响应式原理

使用 object.defindProperty() 进行数据劫持 深度监听实现
响应式原理的实现过程,声明一个普通

let obj = {
name: ‘小铭’,
age: 20,
b:{
index:10,
c:{
n:20
}
},
ary:[11,22,33,44]
}

// 获取数组的原型 原型上有数组的基础方法[push,pot]等等
const oldAryproto =  Array.prototype
// 定义一个对象  对象原型使用数组的原型 
const newAryproto =  Object.create(oldAryproto)
// 可以得到结果 newAryproto.__proto__  ===  Array.prototype   返回 true

定义一个基础数组 数组的内容用数组原型的方法名称
let aryList = ['push','pop','shift','unshift','sort','splice','reverse']

循环这个数组 给我们的对象加入key和value,key是我们的数组方法名称(如:push,pot) value 就是一个普通的function(){}
得到的对象是这种函数结构
{
    push:fn(){},
    pop:fn(){},
    shift:fn(){},
}
在每一个函数中调用该原型上的对应函数进行数组的操作  
...arguments引用修改值,用来修改数组
oldAryproto[element].call(this,...arguments)

写法如下:
aryList.forEach(element => {
    newAryproto[element] = function(){
        // 当对象的指定函数被调用时  触发(Array.prototype)数组原型上面对应的方法修改数组
        console.log('对象上的方法被触发,就表示监听到了视图的更新动作,但是这里并不能修改数组,必须进行下面的操作才是真实的修改数组')
        // 进行数组修改  调用数组的原型方法 修改数组
        oldAryproto[element].call(this,...arguments)
    }
});

    
    
obServer 判断修改的数据类型 是object 还是 array  并进行处理
function obServer(target) {
    判断 target 如果不是object 或者是null 则直接返回target  进行接下去的处理
    if (typeof target !== 'object' || target === null) {
        return target
    }
    
    //如果是数组类型进行下面的操作:修改数组的原型,指向我们定义的对象,我们定义的对象上注册了数组的对应的操作方法(push,pop,shift等等)但是这些方法是一个普通函数,当这个函数被调用时,不会直接修改数组,而我们newAryproto这个对象,他的__proto__ 是指向我们的Array.prototype(数组原型)  所有只要调用我们这个newAryproto上面的方法,然后同步触发,原型上的方法修改数组,就能监听到视图的变化 并且通过原型上方法的调用修改掉我们的数组
    if(Array.isArray(target)){
    将数组的原型,指向了定义的对象
      target.__proto__ = newAryproto
    }
    
   如果对象类型是 target { status: { name:'xiaoming'} }   是无法通过set进行监听值变化的 
   栗子: status.name = '小红'
    
   进行处理:
   变成普通的name:'xiaoming'
   key 值为 name 
   value 值为 小铭 
   target :{name:'小铭'}
   上面这种才能被set 监听到值修改
   
   使用下面的方法进行递归处理
   for (let key in target) {
        this.defindReactive(target, key, target[key])
    }
}

function defindReactive(target, key, val) {
    // obServer 重复检查value 是不是满足条件
    a:10 (满足) 
    a:{age:10}(不满足的)
    所有需要在这里调用obServer进行递归检查,确保最终被监测的key:value 都是普通类型
    obServer(val)
    
    Object.defineProperty(target, key, {
        get: function () {
            console.log('获取值', val)
            return val;
        },
        set: function (newValue) {
            //  当我们直接将某个属性的value 
            进行修改成一个 栗子:obj.a = {number:10}
            并且立刻obj.a.number++
            这里的value 直接修改成了一个对象 
            如果不进行obServer 递归检测  
            他的多次修改值 只会被监听一次 
            视图更新只会被输出一次
            obServer(newValue)
            if (val !== newValue) {
                console.log('视图更新')
                val = newValue
            }
        }
    })
}
// obServer 响应式数据修改时,判断数据类型并进行对应的处理,保证不同数据在修改时都能被监听到
obServer(obj)

//修改数组 会调用我们定义的数组的方法去监听数组的变化 然后在调用原型上对应的数组方法进行修改数组
obj.ary.push('50')
console.log(obj.ary,'------')

// 修改对象的属性会被set 监听到
obj.name = '小红'

// 深度修改  通过上面的递归 obServer方法 也能监听到值的修改
obj.b.c.n = 80

// 直接修改属性值为一个对象 然后继续二次修改对象内的number值
我们在赋值操作前,使用obServer的方法对新的value值进行检测,如果是对象继续进行处理,那么我们即使在直接赋值,set就会每次更新都进行监听,避免出现修改多次只监听一次的情况出现 
obj.b = {
    number:50
}
obj.number++
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享