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 相关文章推荐
js监听表单value的修改同步问题,跨浏览器支持
Dec 31 Javascript
js相册效果代码(点击创建即可)
Apr 16 Javascript
jquery的clone方法应用于textarea和select的bug修复
Jun 26 Javascript
jQuery中:focus选择器用法实例
Dec 30 Javascript
jQuery超赞的评分插件(8款)
Aug 20 Javascript
jQuery实现的数值范围range2dslider选取插件特效多款代码分享
Aug 27 Javascript
JS实现漂亮的时间选择框效果
Aug 20 Javascript
关于使用axios的一些心得技巧分享
Jul 02 Javascript
Vue.js弹出模态框组件开发的示例代码
Jul 26 Javascript
jquery使用iscorll实现上拉、下拉加载刷新
Oct 26 jQuery
详解ES6中的 Set Map 数据结构学习总结
Nov 06 Javascript
解决await在forEach中不起作用的问题
Feb 25 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
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
2013/06/29 PHP
PHP魔术方法使用方法汇总
2016/02/14 PHP
Ubuntu上安装yaf扩展的方法
2018/01/29 PHP
掌握PHP垃圾回收机制详解
2019/03/13 PHP
jQuery ui1.7 dialog只能弹出一次问题
2009/08/27 Javascript
关于IE、Firefox、Opera页面呈现异同 写脚本很痛苦
2009/08/28 Javascript
表格 隔行换色升级版
2009/11/07 Javascript
juqery 学习之六 CSS--css、位置、宽高
2011/02/11 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
基于JS实现简单的样式切换效果代码
2015/09/04 Javascript
JavaScript实现99乘法表及隔行变色实例代码
2016/02/24 Javascript
用自定义图片代替原生checkbox实现全选,删除以及提交的方法
2016/10/18 Javascript
node.js中express-session配置项详解
2017/05/31 Javascript
vue 查看dist文件里的结构(多种方式)
2020/01/17 Javascript
Python的垃圾回收机制深入分析
2014/07/16 Python
基于python爬虫数据处理(详解)
2017/06/10 Python
MAC中PyCharm设置python3解释器
2017/12/15 Python
python使用turtle库绘制时钟
2020/03/25 Python
Python 实现「食行生鲜」签到领积分功能
2018/09/26 Python
python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
2019/04/01 Python
Apache部署Django项目图文详解
2019/07/30 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
pymysql之cur.fetchall() 和cur.fetchone()用法详解
2020/05/15 Python
python一些性能分析的技巧
2020/08/30 Python
Python+OpenCV图像处理——实现直线检测
2020/10/23 Python
美国知名艺术画网站:Art.com
2017/02/09 全球购物
BRASTY捷克:购买香水、化妆品、手袋和手表
2017/07/12 全球购物
sleep()方法和wait()方法的区别是什么
2012/11/17 面试题
安全生产承诺书
2014/03/26 职场文书
生活小常识广播稿
2014/09/16 职场文书
2016思想纪律作风整顿心得体会
2016/01/23 职场文书
2016大学先进团支部事迹材料
2016/03/01 职场文书
python执行js代码的方法
2021/05/13 Python
详细总结Python常见的安全问题
2021/05/21 Python
vue项目如何打包之项目打包优化(让打包的js文件变小)
2022/04/30 Vue.js
Beekeeper Studio开源数据库管理工具比Navicat更炫酷
2022/06/21 数据库