使用 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