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 Tools tab使用介绍
Jul 14 Javascript
Jquery实现自定义弹窗示例
Mar 12 Javascript
Js操作树节点自动折叠展开的几种方法
May 05 Javascript
JavaScript DOM进阶方法
Apr 13 Javascript
Kotlin学习第一步 kotlin语法特性
May 25 Javascript
JavaScript 基础表单验证示例(纯Js实现)
Jul 20 Javascript
vue2.0的contextmenu右键弹出菜单的实例代码
Jul 24 Javascript
微信公众号H5支付接口调用方法
Jan 10 Javascript
解决vue项目F5刷新mounted里的函数不执行问题
Nov 05 Javascript
Vue 一键清空表单的实现方法
Feb 07 Javascript
Vue路由守卫及页面登录权限控制的设置方法(两种)
Mar 31 Javascript
js制作提示框插件
Dec 24 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
简单易用的计数器(数据库)
2006/10/09 PHP
php多种形式发送邮件(mail qmail邮件系统 phpmailer类)
2014/01/22 PHP
php实现信用卡校验位算法THE LUHN MOD-10示例
2014/05/07 PHP
php中strstr、strrchr、substr、stristr四个函数的区别总结
2014/09/22 PHP
Yii2框架dropDownList下拉菜单用法实例分析
2016/07/18 PHP
PHP大文件切割上传功能实例分析
2019/07/01 PHP
Jquery AutoComplete自动完成 的使用方法实例
2010/03/19 Javascript
JavaScript Chart 插件整理
2010/06/18 Javascript
基于JavaScript如何制作遮罩层对话框
2016/01/26 Javascript
jQuery简单验证上传文件大小及类型的方法
2016/06/02 Javascript
AngularJS利用Controller完成URL跳转
2016/08/09 Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
2016/12/27 Javascript
jQuery选择器实例应用
2017/01/05 Javascript
jQuery插件FusionCharts绘制2D柱状图和折线图的组合图效果示例【附demo源码】
2017/04/10 jQuery
微信小程序实现页面跳转传值以及获取值的方法分析
2017/12/18 Javascript
vue+iview+less+echarts实战项目总结
2018/02/22 Javascript
详解如何使用nvm管理Node.js多版本
2019/05/06 Javascript
Vue修改项目启动端口号方法
2019/11/07 Javascript
[03:35]2018年度DOTA2最佳辅助位选手5号位-完美盛典
2018/12/17 DOTA
Python写的Tkinter程序屏幕居中方法
2015/03/10 Python
Python使用scrapy采集时伪装成HTTP/1.1的方法
2015/04/08 Python
Python中的urllib模块使用详解
2015/07/07 Python
Python列表删除的三种方法代码分享
2017/10/31 Python
Python:Numpy 求平均向量的实例
2019/06/29 Python
python如何实现异步调用函数执行
2019/07/08 Python
简单瞅瞅Python vars()内置函数的实现
2019/09/27 Python
python实现五子棋程序
2020/04/24 Python
IntelliJ 中配置 Anaconda的过程图解
2020/06/01 Python
威尔逊皮革:Wilsons Leather
2018/12/07 全球购物
如何开发安全的AJAX应用
2014/03/26 面试题
俄语翻译实习生的自我评价分享
2013/11/06 职场文书
中医专业职业生涯规划书范文
2014/01/04 职场文书
大学军训感想
2014/02/12 职场文书
《一面五星红旗》教学反思
2016/02/23 职场文书
Go 通过结构struct实现接口interface的问题
2021/10/05 Golang
Nginx安装配置详解
2022/06/25 Servers