初识:
- 实际上是通过Object.defineProperty()方法来实现的
- talk is cheap, show your code
let obj = {};
Object.defineProperty(obj, 'name', {
get(){
return document.querySelector('#name').innerHTML;
},
set(newVal){
document.querySelector('#name').innerHTML = val;
}
})
封装:
class Lz{
constructor(options){
this.$options = options;
this.$data = options.data;
this.observe(this.$data);
}
observe(value){
if(!value || typeof value !== 'object'){
return;
}
Object.keys(value).forEach(key =>{
this.defineReactive(value, key, value[key])
})
}
defineReactive(obj, key, val){
Object.defineProperty(obj, key,{
get(){
return val
},
set(newVal){
if(val === newVal) return;
console.log(`数据更新辣: ${val} --- > ${newVal}`);
val = newVal;
}
})
}
}
引用Lz类
<body>
<div id="app"></div>
<script src="./lz.js"></script>
<script>
const app = new Lz({
el:'#app',
data:{
foo:'bar',
hello:{
world:'您好,世界'
}
}
})
</script>
</body>
- 打开浏览器,在控制台输入app.$data.foo
- 尝试改变app.$data.foo的值
- 尝试改变app.$data.hello.world的值

浅拷贝
- 以上,对第一个属性foo的操作成功的触发了set函数.
- 由于浅拷贝复制的是引用,我们对对象的修改无法触发set.
- 简单的理解就是set只负责监听自己这一层的变化,下一层的变化.不予监听
- 解决办法,使用递归.给每一层添加一个setter方法.代码如下
- 只需在defineReactive里面对world对象设置set和get
- 重写defineReactive方法
defineReactive(obj, key, val){
this.observe(val);
Object.defineProperty(obj, key, {
get(){
return val;
},
set(newVal){
if(newVal === val){
return;
}
console.log(`${key}属性更新: ${val} --- > ${newVal}`);
val = newVal;
}
})
}