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 validate.js表单验证的基本用法入门
May 13 Javascript
javascript之典型高阶函数应用介绍二
Jan 10 Javascript
javascript常用对话框小集
Sep 13 Javascript
Vue表单实例代码
Sep 05 Javascript
js微信支付实现代码
Dec 22 Javascript
jQuery插件扩展操作入门示例
Jan 16 Javascript
bootstrap时间插件daterangepicker使用详解
Oct 19 Javascript
微信小程序scroll-view组件实现滚动动画
Jan 31 Javascript
总结JavaScript在IE9之前版本中内存泄露问题
Apr 28 Javascript
浅析Vue.js中v-bind v-model的使用和区别
Dec 04 Javascript
jquery轻量级数字动画插件countUp.js使用详解
Oct 17 jQuery
JS如何监听div的resize事件详解
Dec 03 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 setcookie指定domain参数后,在IE下设置cookie失效的解决方法
2011/09/09 PHP
浅谈php安全性需要注意的几点事项
2014/07/17 PHP
php图片水印添加、压缩、剪切的封装类实现
2020/04/18 PHP
php-msf源码详解
2017/12/25 PHP
Laravel 6.2 中添加了可调用容器对象的方法
2019/10/22 PHP
javascript 进阶篇2 CSS XML学习
2012/03/14 Javascript
JS实现淘宝幻灯片效果的实现方法
2013/03/22 Javascript
Javascript中string转date示例代码
2013/11/01 Javascript
浅谈javascript面向对象程序设计
2015/01/21 Javascript
jquery实现表单验证并阻止非法提交
2015/07/09 Javascript
javascript常用函数(1)
2015/11/04 Javascript
从重置input file标签中看jQuery的 .val() 和 .attr(“value”) 区别
2016/06/12 Javascript
js实现文本上下来回滚动
2017/02/03 Javascript
详解Vue 事件修饰符capture 的使用
2017/12/29 Javascript
详解webpack-dev-server 设置反向代理解决跨域问题
2018/04/18 Javascript
JavaScript设计模式之工厂模式简单实例教程
2018/07/03 Javascript
Vue使用JSEncrypt实现rsa加密及挂载方法
2020/02/07 Javascript
Ajax获取node服务器数据的完整步骤
2020/09/20 Javascript
python实现中文输出的两种方法
2015/05/09 Python
Python实现登录接口的示例代码
2017/07/21 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
Python os.rename() 重命名目录和文件的示例
2018/10/25 Python
Python实现的ftp服务器功能详解【附源码下载】
2019/06/26 Python
Python如何实现在字符串里嵌入双引号或者单引号
2020/03/02 Python
在服务器上安装python3.8.2环境的教程详解
2020/04/26 Python
python调用jenkinsAPI构建jenkins,并传递参数的示例
2020/12/09 Python
python 邮件检测工具mmpi的使用
2021/01/04 Python
HTML5 播放 RTSP 视频的实例代码
2019/07/29 HTML / CSS
优秀求职信范文分享
2014/01/26 职场文书
公司新年寄语
2014/04/04 职场文书
优秀毕业生就业推荐信
2014/05/22 职场文书
大学生工作求职信
2014/06/23 职场文书
珍惜资源的建议书
2014/08/26 职场文书
贷款收入证明范本
2015/06/12 职场文书
开学典礼观后感
2015/06/15 职场文书
Mysql调整优化之四种分区方式以及组合分区
2022/04/13 MySQL