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 相关文章推荐
获取JavaScript用户自定义类的类名称的代码
Mar 08 Javascript
jqPlot 图表中文API使用文档及源码和在线示例
Feb 07 Javascript
上传的js验证(图片/文件的扩展名)
Apr 25 Javascript
jQuery 1.9移除了$.browser可以使用$.support来替代
Sep 03 Javascript
Angular.Js的自动化测试详解
Dec 09 Javascript
JavaScript利用正则表达式替换字符串中的内容
Dec 12 Javascript
javascript十六进制数字和ASCII字符之间的转换方法
Dec 27 Javascript
详解Vue监听数据变化原理
Mar 08 Javascript
javascript实现日期三级联动下拉框选择菜单
Dec 03 Javascript
使用node.js实现微信小程序实时聊天功能
Aug 13 Javascript
微信小程序功能之全屏滚动效果的实现代码
Nov 22 Javascript
Vue请求java服务端并返回数据代码实例
Nov 28 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
基于magic_quotes_gpc与magic_quotes_runtime的区别与使用介绍
2013/04/22 PHP
详解在PHP的Yii框架中使用行为Behaviors的方法
2016/03/18 PHP
Ajax提交表单时验证码自动验证 php后端验证码检测
2016/07/20 PHP
PHP发送邮件确认验证注册功能示例【修改别人邮件类】
2019/11/09 PHP
PHP实现获取文件mime类型多种方法解析
2020/05/28 PHP
参考:关于Javascript中实现暂停的几篇文章
2007/03/04 Javascript
基于IE下ul li 互相嵌套时的bug,排查,解决过程以及心得介绍
2013/05/07 Javascript
如何学习Javascript入门指导
2013/11/01 Javascript
seajs中模块的解析规则详解和模块使用总结
2014/03/12 Javascript
常见的jQuery选择器汇总
2014/11/24 Javascript
推荐一个自己用的封装好的javascript插件
2015/01/29 Javascript
JS+CSS实现大气的黑色首页导航菜单效果代码
2015/09/10 Javascript
jQuery基础的工厂函数以及定时器的经典实例分析
2016/05/20 Javascript
jQuery模仿京东/天猫商品左侧分类导航菜单效果
2016/06/29 Javascript
兼容浏览器的js事件绑定函数(详解)
2017/05/09 Javascript
React数据传递之组件内部通信的方法
2017/12/31 Javascript
微信小程序制作表格的方法
2019/02/14 Javascript
JS中的算法与数据结构之链表(Linked-list)实例详解
2019/08/20 Javascript
[57:09]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第一场 1月26日
2021/03/11 DOTA
Python爬取三国演义的实现方法
2016/09/12 Python
Python Xml文件添加字节属性的方法
2018/03/31 Python
详解Python连接MySQL数据库的多种方式
2019/04/16 Python
12个步骤教你理解Python装饰器
2019/07/01 Python
python 基于DDT实现数据驱动测试
2021/02/18 Python
美国折扣网站:jClub
2017/08/07 全球购物
Opodo意大利:欧洲市场上领先的在线旅行社
2019/10/24 全球购物
Internet主要有哪些网络群组成
2015/12/24 面试题
四风存在的原因分析
2014/02/11 职场文书
秋天的雨教学反思
2014/04/27 职场文书
努力学习演讲稿
2014/05/10 职场文书
学生抄作业检讨书(2篇)
2014/10/17 职场文书
关于群众路线的心得体会
2014/11/05 职场文书
2016年大学生社会实践心得体会
2015/10/09 职场文书
JavaScript实现淘宝商品图切换效果
2021/04/29 Javascript
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
2021/07/01 MySQL
MutationObserver在页面水印实现起到的作用详解
2022/07/07 Javascript