/**
* 可以帮我们事先对对象里面的所有属性进行劫持
* */
class Observe{
constructor(obj){
this.observe(obj)
}
observe(obj){
if(obj&&typeof obj=='object'){
for(let attr in obj){
this.defineReactive(obj,attr,obj[attr])
}
}
}
/**
* obj待处理的对象
* attr 对象的属性
* value 进行get/set 操作的是value
* */
defineReactive(obj,attr,value){
this.observe(value);//对value需要进一步的进行劫持
Object.defineProperty(obj,attr,{
get(){
return value;
},
set:(newValue)=>{
if(value!==newValue){
this.observe(newValue);//判断新设置的值是否是对象,如果是对象,也需要被劫持
value=newValue;
console.log('set操作,数据变化了,视图进行更新',newValue);
}
}
})
}
}
<script>
const obj={
id:1,
name:'andy',
age:{
n:23
}
}
new Observe(obj)
obj.age={
n:50}
obj.age.n=54
console.log(obj);
</script>
1.constructor构造函数
?constructor(obj){
? ? ? ? this.observe(obj)
? ? }是初始化Observe类,将所传入类的参数,可以通过constructor参数的obj中获取
这里的this是代表Observe这个类的this,调用这个类里面的observe方法
2.observe方法定义逻辑
? ? observe(obj){
? ? ? ? if(obj&&typeof obj=='object'){
? ? ? ? ? ? for(let attr in obj){
? ? ? ? ? ? ? ? this.defineReactive(obj,attr,obj[attr])
? ? ? ? ? ? }
? ? ? ? }
? ? }是对象与数组劫持所以首先判断传入的类型,是否符合
通过for in的方式将,对象的key,value,对象遍历出来,循环调用defineReactive,将数据传入
3.数据劫持关键代码
?defineReactive(obj,attr,value){
? ? ? ? this.observe(value);//对value需要进一步的进行劫持
? ? ? ? Object.defineProperty(obj,attr,{
? ? ? ? ? ? get(){
? ? ? ? ? ? ? ? return value;
? ? ? ? ? ? },
? ? ? ? ? ? set:(newValue)=>{
? ? ? ? ? ? ? ? if(value!==newValue){
? ? ? ? ? ? ? ? ? ? this.observe(newValue);?
? ? ? ? ? ? ? ? ? ? value=newValue;
? ? ? ? ? ? ? ? ? ? console.log('set操作,数据变化了,视图进行更新',newValue);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }(1).先看Object.defineProperty
get是监听获取对象中值的时候,会执行
set是监听设置的时候会执行
为什么在set箭头函数内,再次调用this.observe是因为放置所设置的值是对象,若是对象则继续执行监听,不是则停止,observe有判断拦截
(2).一开始上来就先调用this.observe(value)
因为对象内也可以再声明对象,若没有再次以递归的方式调用一次,则无法监听,多个对象执行修改
如下:
new Observe(obj)
obj.age={n:50}
obj.age.n=54