Vue Object 的变化侦测实现代码


Posted in Javascript onApril 15, 2020

数据观察

Vue 中的对象变化侦测是通过Object.definePorperty实现的,但是Object.definePorperty的方式有缺陷,比如不能直接代理整个对象,每次都要循环遍历对象的所有属性;尤大大说之后会使用 ES6 中的Proxy 重写这个部分。这篇博客介绍的是 Object.definePorperty 实现的对象侦测。

我们来看下面这段代码,定义一个 defineReactive 函数,使用 Object.definePorperty 遍历对象对象属性的时候,设置 get 和 set;当对象属性被读取的时候触发 get,对象属性被设置的时候触发 set。这样就完成了对 data 的数据劫持,因为 Vue 的思想是响应式的,我们还需要收集这些变化。

function defineReactive(data,key,val){
  Object.definePorperty(data,key,{
    enumerable: true,
    configurable: true,
    get:function(){
      return val;
    }
    set :function (newVal){
      if(val === newVal){return}
      val = newVal;
    }
  })
}

依赖 收集

创建一个 Dep 类,在 get 中收集依赖,在 set 中新增依赖

class Dep{
  constructor(){
    this.arr = []
  }
  addSub(sub){
    this.arr.push(sub)
  }
   removeSub(sub){
    remove(this.arr,sub)
  }
  depend(){
    if(window.target){
      this.addSub(window.target)
    }
  }
  notify(){
    const arrs = this.arr.slice();
    for(let i = 0; i< arrs.lenth ;i ++){
      arrs[i].update();
    }
  }

}

function defineReactive(data,key,val){

  let dep = new Dep()
  Object.definePorperty(data,key,{
    enumerable: true,
    configurable: true,
    get:function(){
      dep.depend(); // 收集依赖
      return val;
    }
    set :function (newVal){
      if(val === newVal){return}
      val = newVal;
      dep.notify(); // 新增依赖
    }
  })
}

Observer 和 Watcher

我们发现 defineReactive 函数只能将某一个属性转换为 get/set 的形式,所以我们需要一个观察者 Observer 用来帮助递归的侦测所有的 key

class Observer{
  constructor(value){
    this.value = value
  }
  if(!Array.isArry(value)){
    this.walk(value)
  }
  walk(obj){
    const keys = Object.keys(obj)
    for(let i = 0; i < keys.length ;i++){
      defineReactive(data,keys[i],obj[keys[i])
    }
  }
}

当这些依赖收集完成之后,我们要通知谁呢?怎么样能让视图知道有变化更新?我们需要实现一个订阅者 Watcher,
每次触发 get 的时候都将 dep 指向自己,这样就可以收集到依赖;
每次 set 的时候都循环调用 Watcher 的 update 方法。

class Watcher{
  constructor(vm,exp,cb){
    this.vm = vm;
    this.cb = cb;
    this.exp = exp;
    this.value = this.get();
  }
  get(){
    Dep.target = this;  // 将当前订阅者指向自己
    var value = this.vm[exp];  // 触发getter,添加自己到属性订阅器中
    Dep.target = null;  // 添加完毕,重置
    return value;
  }
  update(){
    const oldVal = this.value;
    this.value = this.get();
    this.cb.call(this.vm,this.value,oldVal)
  }
}

当 Vue 实例挂载好之后,模板都会绑定一个 Watcher,谁的属性发生变化了就会通知响应的 Watcher,Watcher 再去通知编译器 Compile 进行视图更新

侦测没办法监听到对象上属性的新增和删除

Vue 通过Object.definePorperty将对象的 key 转化为 getter setter 的形式来进行侦测,但是无法追踪到属性的新增和删除,所以 Vue 中提供了 vm.get 来实现

到此这篇关于Vue Object 的变化侦测实现代码的文章就介绍到这了,更多相关Vue Object 变化侦测 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery 在光标定位的地方插入文字的插件
May 10 Javascript
javascript 快速排序函数代码
May 30 Javascript
JavaScript网页定位详解
Jan 13 Javascript
JavaScript中创建对象和继承示例解读
Feb 12 Javascript
javascript实现延时显示提示框特效代码
Apr 27 Javascript
JavaScript中的各种操作符使用总结
May 26 Javascript
利用D3.js实现最简单的柱状图示例代码
Dec 09 Javascript
bootstrap table 多选框分页保留示例代码
Mar 08 Javascript
Vue单文件组件的如何使用方式介绍
Jul 28 Javascript
JavaScript实现多叉树的递归遍历和非递归遍历算法操作示例
Feb 08 Javascript
JS实现对json对象排序并删除id相同项功能示例
Apr 18 Javascript
如何解决React官方脚手架不支持Less的问题(小结)
Sep 12 Javascript
Vue项目vscode 安装eslint插件的方法(代码自动修复)
Apr 15 #Javascript
小程序按钮避免多次调用接口和点击方案实现(不用showLoading)
Apr 15 #Javascript
javascript设计模式 ? 享元模式原理与用法实例分析
Apr 15 #Javascript
javascript设计模式 ? 外观模式原理与用法实例分析
Apr 15 #Javascript
写给新手同学的vuex快速上手指北小结
Apr 14 #Javascript
vue-cli设置publicPath小记
Apr 14 #Javascript
vue 实现用户登录方式的切换功能
Apr 14 #Javascript
You might like
用PHP实现将GB编码转换为UTF8
2006/11/25 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
新浪SAE搭建PHP项目教程
2015/01/28 PHP
javascript 函数调用的对象和方法
2010/07/01 Javascript
jquery复选框全选/取消示例
2013/12/30 Javascript
jquery实现带渐变淡入淡出并向右依次展开的多级菜单效果实例
2015/08/22 Javascript
JS密码生成与强度检测完整实例(附demo源码下载)
2016/04/06 Javascript
JavaScript对Json的增删改属性详解
2016/06/02 Javascript
AngularJS基础 ng-copy 指令实例代码
2016/08/01 Javascript
微信小程序 location API实例详解
2016/10/02 Javascript
JavaScript实现经典排序算法之冒泡排序
2016/12/28 Javascript
详解支持Angular 2的表格控件
2017/01/19 Javascript
JS滚动到指定位置导航栏固定顶部
2017/07/03 Javascript
vue微信分享出来的链接点开是首页问题的解决方法
2018/11/28 Javascript
超好用的jQuery分页插件jpaginate用法示例【附源码下载】
2018/12/06 jQuery
详解使用angular框架离线你的应用(pwa指南)
2019/01/31 Javascript
JS实现的tab切换并显示相应内容模块功能示例
2019/08/03 Javascript
vue中实现高德定位功能
2019/12/03 Javascript
vue 页面跳转的实现方式
2021/01/12 Vue.js
Python中bisect的用法
2014/09/23 Python
python3序列化与反序列化用法实例
2015/05/26 Python
浅谈Python爬取网页的编码处理
2016/11/04 Python
Python实现的密码强度检测器示例
2017/08/23 Python
python matplotlib 在指定的两个点之间连线方法
2018/05/25 Python
Python实现查询某个目录下修改时间最新的文件示例
2018/08/29 Python
Python for循环与range函数的使用详解
2019/03/23 Python
python+selenium select下拉选择框定位处理方法
2019/08/24 Python
关于Keras模型可视化教程及关键问题的解决
2020/01/24 Python
Python中三维坐标空间绘制的实现
2020/09/22 Python
美国棒球装备和用品商店:Baseball Savings
2018/06/09 全球购物
教师考察材料范文
2014/06/03 职场文书
2014年青年教师工作总结
2014/12/17 职场文书
上市公司董事长岗位职责
2015/04/16 职场文书
2015年秋季小班开学寄语
2015/05/27 职场文书
小学生组织委员竞选稿
2015/11/21 职场文书
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python