Observer
的功能
-
负责把
data
选项中的属性转换成响应式数据 -
data
中的某个属性也是对象,把该属性转换成响应式数据(例如data
中的某个属性为Student
对象,也要将Student
对象中的属性转换成响应式) -
数据变化发送通知
observer.js
文件中的基本代码如下:
class Observer {
constructor(data) {
this.walk(data);
}
walk(data) {
//1、判断data是否是对象,以及data是否为空
if (!data || typeof data !== "object") {
return;
}
// 2、遍历data对象中的所有属性
Object.keys(data).forEach((key) => {
this.defineReactive(data, key, data[key]);
});
}
defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
return val;
},
set(newVal) {
if (newVal === val) {
return;
}
val = newVal;
//发送通知,更新视图
},
});
}
}
下面对以上代码进行测试。
class Vue {
constructor(options) {
// 1、通过属性保存选项的数据
// options:表示在创建Vue实例的时候传递过来的参数,将其保存到$options中。
this.$options = options || {};
//获取参数中的data属性保存到$data中.
this.$data = options.data || {};
//如果是字符串,转成dom对象
this.$el =
typeof options.el === "string"
? document.querySelector(options.el)
: options.el;
// 2、把data中的成员转换成getter和setter,注入到vue实例中.
this._proxyData(this.$data);
//3.调用observer对象,监听数据的变化
new Observer(this.$data);
//4.调用compiler对象,解析指令和差值表达式
}
}
在Vue
类的构造方法中的第三部,创建Observer
的实例,同时传递data
数据。
在index.html
文件中,导入observer.js
文件
<script src="./js/observer.js"></script>
<script src="./js/vue.js"></script>
注意:由于在vue.js
文件中使用了Observer
对象,所以这里先导入observer.js
文件。
下面我们修改一下代码,看一下效果:
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "Hello World",
count: 12,
},
});
console.log(vm.msg);
</script>
在index.html
中,我们打印输出了vm
中的msg
的值,
这时候,会执行vue.js
文件中的get
方法,也会执行observer.js
文件中的get
方法。
如果将observer.js
文件中的get
方法修改成如下形式
get() {
return obj[key];
},
会出现如下错误:
以上错误信息的含义为:堆栈溢出
为什么会出现以上错误呢?
因为obj
就是data
对象,而通过obj[key]
的方式来获取值,还是会执行get
方法,所以这里形成了死循环。