「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。
vue2的实现(5)之对象劫持的一些细节处理二
回顾
-
上次内容我们处理了一个问题,假如用户重新给数据赋值为对象类型的数据,那我们就观测不到这个数据了。因为在属性的
set方法中,我们可以劫持到用户设置数据的操作,所以我们需要在这里对用户设置的值,再做一次观测,我们只要observe(newValue)就可以了,下面是rewrite-vue/src/observe/index.js中的代码。 -
rewrite-vue/src/observe/index.jsclass Observe { consturctor(data){ this.walk(data) } walk(data){ Object.keys(data).forEach(key => defineReactive(data, key, data[key])) } } export function defineReactive(target, key, value){ Object.defineProperty(target, key, { get(){ console.log('劫持用户的取值操作,get'); return value }, set(newValue){ if(newValue !== value){ console.log('劫持用户的设置操作,set'); observe(newValue) value = newValue } } }) } export function observe(data){ if(typeof data !== 'object' || data === null){ return } return new Observe(data) }
观测不到嵌套深层的对象
-
我们用下面的代码测试一下,在浏览器打开
rewrite-vue/dist/index.html。 -
rewrite-vue/dist/index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue2</title> </head> <body> <script src="./vue.js"></script> <script> const vm = new Vue({ data:{ name:'vue2', age: { num:666, key:'age' } } }) console.log(vm._data.age.key); vm._data.age.num = 999 </script> </body> </html> -
下面的图片是输出结果,我们可以看到
console.log(vm._data.age.key)只打印了一次get的输出。vm._data.age.num = 999只打印了一次get的输出。 -
按理说,我们访问
vm._data.age.key,在访问age时打印一次get,在访问key的时候也应该打印一次get。在设置vm._data.age.num = 999的时候,访问age属性时打印一次get输出,设置num属性时要打印一次set的输出。 -
所以说,我们在
defineReactive中需要对每个对象的属性再次进行观测,因为有的属性有可能是对象类型的数据,对于对象类型的数据我们需要进行递归观测,这样在用户进行获取和设置的时候,我们才可以劫持到用户的操作。 -
rewrite-vue/src/observe/index.jsclass Observe { consturctor(data){ this.walk(data) } walk(data){ Object.keys(data).forEach(key => defineReactive(data, key, data[key])) } } export function defineReactive(target, key, value){ observe(value) Object.defineProperty(target, key, { get(){ console.log('劫持用户的取值操作,get'); return value }, set(newValue){ if(newValue !== value){ console.log('劫持用户的设置操作,set'); observe(newValue) value = newValue } } }) } export function observe(data){ if(typeof data !== 'object' || data === null){ return } return new Observe(data) }
测试
-
rewrite-vue/dist/index.html里面的代码还是上面的测试用例,我们再次在浏览器中打开rewrite-vue/dist/index.html可以看到。 -
从下面的图可以看出我们的打印已经生效了,而且打印的内容也和我们所设想的一样,证明我们的修改已经生效了。
今天是更文第十二天加油~ 看到这里兄弟帮忙点个赞吧