1 //数据源
2 let data = {
3 message: "hello word",
4 info: {
5 job: "web It",
6 level: "p8"
7 }
8 };
9 //对数据源劫持拦截
10 class Observer {
11 constructor(data) {
12 //需要观察劫持的对象
13 this.data = data;
14 //给对象设置get,set
15 this.observer(this.data);
16 }
17 observer(data) {
18 //对数据源所有的属性添加get,set
19 Object.keys(data).forEach(key => {
20 this.defineReactive(data, key, data[key]);
21 //如果data[key]还是一个对象
22 if (data[key] instanceof Object) {
23 this.observer(data[key]);
24 }
25 });
26 }
27 defineReactive(data, key, value) {
28 let dep = new Dep();
29 Object.defineProperty(data, key, {
30 enumerable: true,
31 configurable: true,
32 get() {
33 Dep.target && dep.add(Dep.target);
34 return value;
35 },
36 set(newValue) {
37 //如果新旧值变化
38 if (value !== newValue) {
39 value = newValue;
40 dep.notify();
41 }
42 }
43 });
44 }
45 }
46 //定义一个监听watcher
47 class Watcher {
48 constructor(data, key, callback) {
49 //保存数据源
50 this.data = data;
51 //保存取值key
52 this.key = key;
53 //保存回调
54 this.callback = callback;
55 //保存老值
56 this.oldValue = this.get(this.data, this.key);
57 }
58 getExpressionValue(data, expr) {
59 let expression = expr.split("."),
60 [length] = expression;
61 return expression.reduce((prev, next, index) => {
62 if (index === length - 1) {
63 return prev[expression[1]];
64 }
65 return prev[next];
66 }, data);
67 }
68 //触发获取值的操作
69 get(data, key) {
70 //当每一次去数据源获取值的时候把watcher自身赋值给Dep订阅类上
71 Dep.target = this;
72 let val = this.getExpressionValue(data, key);
73 Dep.target = null;
74 return val;
75 }
76 update() {
77 //取出设置完的值就行新旧比对
78 let newValue = this.getExpressionValue(this.data, this.key);
79 newValue !== this.oldValue && this.callback(newValue);
80 }
81 }
82 //创建订阅发布
83 class Dep {
84 constructor() {
85 //订阅者列表
86 this.subscribeLists = new Set();
87 }
88 add(watcher) {
89 //添加订阅
90 this.subscribeLists.add(watcher);
91 }
92 notify() {
93 this.subscribeLists.forEach(watcher => watcher.update());
94 }
95 }
96
97 function getExpressionValue(data, expr) {
98 let expression = expr.split("."),
99 [length] = expression;
100 return expression.reduce((prev, next, index) => {
101 if (index === length - 1) {
102 return prev[expression[1]];
103 }
104 return prev[next];
105 }, data);
106 }
107
108 //取值
109 function getVal(key) {
110 new Watcher(data, key, newValue => {
111 text.innerHTML = newValue;
112 });
113 return getExpressionValue(data, key);
114 }
115 //对数据源进行劫持
116 const observer = new Observer(data);
117
118 let text = document.querySelector("#text");
119 text.innerHTML = getVal("info.level");
120 document.querySelector("#input").addEventListener("input", e => {
121 data.info.level = e.target.value
122 });