Vue2响应式

462 阅读3分钟

vue响应式:它的工作流程对于使用者是隐性的,其数据模型针对的是JavaScript中的对象,当我们修改这些数据时,视图会进行更新; 使用简单的同时,我们也需要对其工作原理进行深究,这样才能找出一些常见的问题;

组件初始化

定义data数据

修改data数据后,页面会更新UI,那么触发这一流程的起点就是修改data数据这一操作,这其中的原理:

Vue中通过 Object.definpropertydata选项 中的数据进行数据劫持;

Object.definproperty,在一个对象上定义一个新属性,或者修改一个对象的现有属性(data选项返回的就是一个对象),语法如下:

/**
 * obj 要定义属性的对象
 * prop 定义的属性名
 * descriptor 属性描述符
 */
Object.defineProperty(obj, prop, descriptor);

var obj = {};
Object.defineProperty(obj, 'field', {
  value: 2,
});
// obj { field: 2 }

属性描述符中这里主要关注 存取描述符

Object.defineProperty(obj, 'field', {
  value: 2,
  // 调用 obj.field 取值时触发;
  // get存在默认会忽略 value;
  get() {},
  // 调用 obj.field 赋值时触发;
  set() {},
});

这些 getter/setter 对用户来说是不可见的;

  • 在属性被访问时,会收集观察者;
  • 在属性修改时,通知观察者变更;

Q: 为什么会存在 setset、delete 方法?

Q:数组并不是常规的对象,也是十分常见的数据格式,vue如何实现对数组变动的劫持?

Q:为什么数组修改length属性、通过下标修改值无法触发更新?

render渲染

当修改了data数据后,vue判断该数据是否会触发页面更新、更新哪一个组件的原理:

每一个组件的render方法,都对应一个观察者实例watcher,在组件渲染时,会将接触到的数据getter,进行记录,当数据setter触发时,会通知watcher重新执行;

new Watcher(render);

如何追踪变化?

1、new Observer() 注册服务

为观察对象(或数组) 提供注册服务,将观察对象的get和set替换为依赖收集、触发器;

2、new Dep() 缓存队列

用来收集观察者 & 触发;

收集的是什么?

3、new Watcher() 观察者

开始收集的起点,执行 表达式 触发对象的 getter 从而达到依赖收集;

表达式是指什么?
表达式可以是一个函数(render、computed),或者注册服务的get,总之就是要触发注册服务的get方法;

依赖是指什么?
一个回调函数,当变量改变时,需要执行的某个方法,比如render;

image.png

回过头来

Q:new Observer() 的对象保存在哪里?

Q:两个new Dep()的应用场景;

Q:render时,因为UI切换导致某些变量不会使用,如何在dep中注销依赖?

Q:dep如何知道当前需要收集的依赖是谁?

watch是如何工作的

watch的三种常见写法:

watch: {
    a: function (newValue) {
        console.log('change a', newValue);
    },
    b: {
        deep: true,
        handler: function (newValue) {
            console.log('change b', newValue);
        },
    },
    'c.d': function (newValue) {
        console.log('change c.d', newValue);
    },
},

new Watcher接受一个表达式,这里的表达式,就是属性本身的 getter函数,通过直接执行变量的getter,触发依赖收集;

image.png

总结

image.png

image.png