变化侦测
Vue.js最独特的特性之一是看起来并不显眼的响应式系统。当数据变化时 ,UI界面跟着变化,所以平时开发只需要关心数据 ,包括样式也是数据。简单来说变化侦测的作用就是着侦测数据的变化,当数据变化时,会通知视图相应的更新。
如何追踪变化
可以通过 Object.defineProperty来监测对象变化 ,Object.defineProperty用法如下
定义:: 静态方法Object.defineProperty()直接在对象上定义一个新属性,或者修改对象上已有的属性,并返回该对象。
Object.defineProperty(obj, prop, descriptor) obj 定义的对象 prop一个字符串 descriptor 被定义或修改的属性的描述符。
kotlin
Object.defineProperty(this, 'message', {
get: function() {
console.log('Getting value:', this._message);
return this._message;
},
set: function(newValue) {
console.log('Setting value to:', newValue);
if (newValue !== this._message) {
this._message = newValue;
this.$forceUpdate(); // 强制更新视图
}
}
});
如何收集依赖 Dep

该模板中使用了数据name,所以当它发生变化时,要向使用了它的地方发送通知。 对于上面的问题是,先收集依赖,用到name的地方收集起来 ,然后等属性发生变化时,把之前收集好的依赖循环触发一遍 总结: 在get中收集依赖 在set中触发依赖
依赖收集在哪里
封装一个dep 类
javascript
class Dep {
constructor() {
// 存储订阅者的集合
this.subscribers = new Set();
}
// 将当前活动的副作用添加到订阅者集合中
depend() {
if (activeEffect) {
this.subscribers.add(activeEffect);
}
}
// 通知所有订阅者重新运行他们的副作用
notify() {
this.subscribers.forEach(effect => effect());
}
}
依赖是谁 Watch
观察者,当依赖的数据变化时,触发回调函数。
kotlin
// Watcher 类:观察者,当依赖的数据变化时,触发回调函数
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
// 获取值,并进行依赖收集
get() {
Dep.target = this;
const value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
// 更新值
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
watcher 是如何与模版关联的
Watcher 主要用于监听数据的变化,并在数据变化时更新视图。为了将 Watcher 与模板关联起来,Vue 使用了一个编译器将模板转换为渲染函数(render function),然后通过这些渲染函数来创建虚拟 DOM(VNode)。当数据发生变化时,Watcher 会触发重新渲染过程,更新实际的 DOM。 一个dom 关联一个watcher 创建相应的 Watcher 实例,并将初始值插入到 DOM 中
Array的变化侦测
获取原始数组原型:
ini
const arrayProto = Array.prototype;
创建新的数组方法对象:
ini
const arrayMethods = Object.create(arrayProto);
定义需要拦截的方法:
ini
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
拦截每个方法并添加响应性逻辑
ini
methodsToPatch.forEach(function (method) {
const original = arrayProto[method];
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args);
const ob = this.__ob__;
let inserted;
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
if (inserted) ob.observeArray(inserted);
ob.dep.notify();
return result;
});
});
它的作用是将拦截器(加工后具备拦截功能的arrayMethods)赋值给value.proto ,通过 proto 可以很巧妙地实现覆盖value原型的功能
kotlin
export class Observer {
constructor (value) {
this.value = value
}
if (Array.isArray(value)) {
value.__proto__ = arrayMethods
} else {
this.walk(value)
}
}
}