let count =0functionObserve(ops){// 这里的ops就是我们的obj,提取ops对象中的所有键名组成的数组const keys = Object.keys(ops)// 循环遍历这个key数组for(let i =0; i < keys.length; i++){// 取到每一个keyconst key = keys[i]// 定义响应式 ops => obj, key => 对象的键名,ops[key] => 对象的键值defineRective(ops, key, ops[key])}}
3. 定义defineRective响应式函数
functiondefineRective(obj, key, value){// 给传过来的值定义get/set
Object.defineProperty(obj, key,{get(){
console.log(1)return value
},set(val){
console.log(2)
value = val
}})}
现在我们可以测试一下,读取obj中的值,获取设置obj中的值,看看能不能打印
const obj ={
a:1,
b:2,
c:3}newObserve(obj)
console.log(obj.a)
obj.a =4
console.log(obj.a)
## 浏览器打印如下:
i am get1
i am set
i am get4
没问题
6. 更新视图(假设)
那么既然读取对象中的数据就要刷新页面,那么我们这里就测试一下,读取一次页面就加1,我们可以在get/set中调用这个这个函数,达到更新视图的作用
functiondefineRective(obj, key, value){// 给传过来的值定义get/set
Object.defineProperty(obj, key,{get(){update()// 更新页面
console.log('i am get')return value
},set(val){update()// 更新页面
console.log('i am set')
value = val
}})}
7. 优化defineRective响应式函数
之前我们测试的是普通的对象,假设现在我们里面对象嵌套对象,那么我们的代码能否实现响应式呢?我们可以测试一下
const obj2 ={
a:{
f:'hello'},
b:{
g:'华哥头发呢?'},
c:3}newObserve(obj2)
console.log(obj2.a.f)
console.log(obj2)// 经过打印obj2发现,只有第一层对象有get/set,所有并没有实现深度相应// 那么我们就可以深度遍历一下,如果对象的值还是一个对象的话,我们可以递归调用Observe函数来为我们的对象添加get/set方法// 响应式functiondefineRective(obj, key, value){// 如果值还是一个对象的话,递归调用一下if(typeof value ==='object')Observe(value)// 给传过来的值定义get/set
Object.defineProperty(obj, key,{get(){update()// 更新页面
console.log('i am get')return value
},set(val){update()// 更新页面
console.log('i am set')
value = val
}})}