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 相关文章推荐
PPK 谈 JavaScript 的 this 关键字 [翻译]
Sep 29 Javascript
JavaScript 事件记录使用说明
Oct 20 Javascript
JavaScript基本编码模式小结
May 23 Javascript
JS实现的一个简单的Autocomplete自动完成例子
Apr 16 Javascript
再JavaScript的jQuery库中编写动画效果的指南
Aug 13 Javascript
jQuery实现只允许输入数字和小数点的方法
Mar 02 Javascript
jQuery siblings()用法实例详解
Apr 26 Javascript
jQuery实现根据滚动条位置加载相应内容功能
Jul 18 Javascript
js表单序列化判断空值的实例
Sep 22 Javascript
JS中注入eval, Function等系统函数截获动态代码
Apr 03 Javascript
Promise扫盲贴
Jun 24 Javascript
js 计算月/周的第一天和最后一天代码
Feb 01 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入门学习知识点三 PHP上传
2011/07/14 PHP
php urlencode()与urldecode()函数字符编码原理详解
2011/12/06 PHP
Zend Studio 实用快捷键一览表(精心整理)
2013/08/10 PHP
详解php协程知识点
2018/09/21 PHP
PHP7 安装event扩展的实现方法
2019/10/08 PHP
关于JavaScript命名空间的一些心得
2014/06/07 Javascript
JavaScript转换二进制编码为ASCII码的方法
2015/04/16 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
2015/12/22 Javascript
jQuery实现元素拖拽并cookie保存顺序的方法
2016/02/20 Javascript
JavaScript实现图像模糊化的方法实例
2017/01/15 Javascript
微信小程序实现下拉框功能
2019/07/16 Javascript
layui form表单提交后实现自动刷新
2019/10/25 Javascript
Vue中this.$nextTick的作用及用法
2020/02/04 Javascript
[55:45]DOTA2上海特级锦标赛D组败者赛 Liquid VS COL第一局
2016/02/28 DOTA
基于scrapy实现的简单蜘蛛采集程序
2015/04/17 Python
python通过配置文件共享全局变量的实例
2019/01/11 Python
对python3.4 字符串转16进制的实例详解
2019/06/12 Python
使用 Python 处理 JSON 格式的数据
2019/07/22 Python
python实现逆滤波与维纳滤波示例
2020/02/26 Python
详解Pycharm出现out of memory的终极解决方法
2020/03/03 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
Python如何急速下载第三方库详解
2020/11/02 Python
HTML5中5个简单实用的API(第二篇,含全屏、可见性、拍照、预加载、电池状态)
2014/05/07 HTML / CSS
详解canvas多边形(蜘蛛图)的画法示例
2018/01/29 HTML / CSS
canvas裁剪clip()函数的具体使用
2018/03/01 HTML / CSS
amazeui 验证按钮扩展的实现
2020/08/21 HTML / CSS
Joie官方网上商店:购买服装和女装配饰
2018/06/05 全球购物
校班主任推荐信范文
2013/12/03 职场文书
自我鉴定怎么写
2014/01/12 职场文书
十佳青年个人事迹材料
2014/01/28 职场文书
文明餐桌行动实施方案
2014/02/19 职场文书
11.9消防日宣传标语
2014/10/08 职场文书
公司员工违纪检讨书
2015/05/05 职场文书
安全生产警示教育活动总结
2015/05/09 职场文书
暑假开始了,你的暑假学习计划写好了吗?
2019/07/04 职场文书
Vue.js中v-bind指令的用法介绍
2022/03/13 Vue.js