找回密码
 立即注册
查看: 131|回复: 5

Vue2 Observer 构造函数 - 数组响应的实现

[复制链接]

9

主题

37

回帖

151

积分

注册会员

积分
151
发表于 2022-9-19 22:07:43 | 显示全部楼层 |阅读模式
本帖最后由 13824597405 于 2022-9-19 22:09 编辑

Vue data 里面可以是对象或者数组, Vue.js 将对象和数组加入到响应式系统中,采用了不同的处理方式.
  1. new Vue({
  2.   el:"#app",
  3.   data:{
  4.     obj:{
  5.       name:"V",
  6.     },
  7.   list:["play","eat"]
  8.   }
复制代码

回复

使用道具 举报

9

主题

37

回帖

151

积分

注册会员

积分
151
 楼主| 发表于 2022-9-19 22:10:17 | 显示全部楼层
通过遍历数组获取数组的每一项, 当做参数传递给 observe(item), observe 是响应式入口, observe 对当做参数传递的进来的值进行过滤, 终加入到响应式系统.
  1. var Observer = function Observer(value) {
  2.      ...
  3.     /* 对数组进行处理 */
  4.     if (Array.isArray(value)) {
  5.         /*对__proto__进行兼容处理*/
  6.         if (hasProto) {
  7.             protoAugment(value, arrayMethods);
  8.         } else {
  9.             copyAugment(value, arrayMethods, arrayKeys);
  10.         }
  11.         this.observeArray(value);
  12.     } else {
  13.         /* 对象的处理 */
  14.         this.walk(value);
  15.     }
  16. };
  17. /**
  18. * Observe a list of Array items.
  19. */
  20. Observer.prototype.observeArray = function observeArray(items) {
  21.     /* 对数组进行遍历, 将每一项传入observe函数中 */
  22.     for (var i = 0, l = items.length; i < l; i++) {
  23.         /* 数组的每一项遍历出来, 当做参数传递给observe, observe 是响应式入口,讲数组的每一项加入到响应式系统*/
  24.         observe(items[i]);
  25.     }
  26. };
复制代码
回复

使用道具 举报

9

主题

37

回帖

151

积分

注册会员

积分
151
 楼主| 发表于 2022-9-19 22:11:05 | 显示全部楼层
有一个问题值得深思: 对象的可以通过 Object.defineProperty函数来进行属性的 getter 访问和 setter 修改进行拦截. 那么数组怎么知道改变了并进行了拦截 ?

Vue.js 将对数组的变化采用的是借壳的思想,也可以说是共享原型的方式. 来探索一下其中的奥秘

对数组改变自身的的变异方法如下, Vue.js已经帮助我们收集了
  1. var methodsToPatch = [
  2.     'push',
  3.     'pop',
  4.     'shift',
  5.     'unshift',
  6.     'splice',
  7.     'sort',
  8.     'reverse'
  9. ];
复制代码
回复

使用道具 举报

9

主题

37

回帖

151

积分

注册会员

积分
151
 楼主| 发表于 2022-9-19 22:11:37 | 显示全部楼层
创建了一个对象, 让该对象的原型对象指向Array.prototype, arrayMethods也就具有了数组的常用的方法
  1. var arrayProto = Array.prototype;
  2. /*创建一个对象, 让该对象指向数组的原型对象*/
  3. var arrayMethods = Object.create(arrayProto);
  4. /*这些方法可以改变数组本身,  数组的变异方法*/
复制代码
回复

使用道具 举报

9

主题

37

回帖

151

积分

注册会员

积分
151
 楼主| 发表于 2022-9-19 22:12:34 | 显示全部楼层
代码实现
  1. /**
  2. * Intercept mutating methods and emit events
  3. */
  4. methodsToPatch.forEach(function (method) {
  5.     // cache original method
  6.     /*缓存当前的method*/
  7.     var original = arrayProto[method];
  8.     //function def(obj, key, val, enumerable)
  9.     def(arrayMethods, method, function mutator() {
  10.         var args = [], len = arguments.length;
  11.         /*通过循环, 将参数转为args数组 */
  12.         while (len--) args[len] = arguments[len];
  13.         /*触发Array.prototype上方法*/
  14.         var result = original.apply(this, args);
  15.         var ob = this.__ob__;
  16.         var inserted;
  17.         /*以下下三个比较特殊, 往数组里面添加数据, 如果加入又是一个数组呢?*/
  18.         switch (method) {
  19.             case 'push':
  20.             case 'unshift':
  21.                 inserted = args;
  22.                 break
  23.             case 'splice':
  24.                 inserted = args.slice(2);
  25.                 break
  26.         }
  27.         /*inserted为true,数组中加入了数据*/
  28.         if (inserted) {
  29.             /* 继续添加数据到响应式系统 */
  30.             ob.observeArray(inserted);
  31.         }
  32.         // notify change
  33.         /*触发依赖更新*/
  34.         ob.dep.notify();
  35.         /*返回result*/
  36.         return result
  37.     });
  38. });
复制代码
回复

使用道具 举报

9

主题

37

回帖

151

积分

注册会员

积分
151
 楼主| 发表于 2022-9-19 22:13:37 | 显示全部楼层
上述代码在调用数组的变异的方法去修改数组, 先会进行拦截. 最终触发(emit)Array.prototype的对应的方法.

但是 'push', 'unshift', 'splice', 可以像数组里添加成员. 如果添加的成员是数组, 获取到添加的新成员, 加入到响应式系统.最后触发依赖的更新
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|粤嵌技术交流空间

GMT+8, 2025-7-7 15:43 , Processed in 0.669714 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表