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 相关文章推荐
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
May 07 Javascript
extjs 时间范围选择自动判断的实现代码
Jun 24 Javascript
Egret引擎开发指南之视觉编程
Sep 03 Javascript
JavaScript保留关键字汇总
Dec 01 Javascript
AngularJS基础 ng-csp 指令详解
Aug 01 Javascript
Vue制作Todo List网页
Apr 26 Javascript
zTree树形插件异步加载方法详解
Jun 14 Javascript
es6中的解构赋值、扩展运算符和rest参数使用详解
Sep 28 Javascript
详解用Node.js实现Restful风格webservice
Sep 29 Javascript
浅谈node的事件机制
Oct 09 Javascript
详解如何在vue项目中使用lodop打印插件
Sep 27 Javascript
区分vue-router的hash和history模式
Oct 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 radio 单选框获取与保持值的实现代码
2010/05/15 PHP
thinkphp框架下实现登录、注册、找回密码功能
2016/04/06 PHP
Yii实现的多级联动下拉菜单
2016/07/13 PHP
PHP中利用sleep函数实现定时执行功能实现代码
2016/08/25 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
Linux基于php-fpm模式的lamp搭建phpmyadmin的方法
2018/10/25 PHP
js cookies实现简单统计访问次数
2009/11/24 Javascript
js parentElement和offsetParent之间的区别
2010/03/23 Javascript
js获取单元格自定义属性值的代码(IE/Firefox)
2010/04/05 Javascript
在新窗口打开超链接的方法小结
2013/04/14 Javascript
浅析JavaScript中的类型和对象
2013/11/29 Javascript
jquerydom对象的事件隐藏显示和对象数组示例
2013/12/10 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
jQuery实现的可编辑表格完整实例
2016/06/20 Javascript
微信小程序 触控事件详细介绍
2016/10/17 Javascript
js实时获取窗口大小变化的实例代码
2016/11/18 Javascript
IE8兼容Jquery.validate.js的问题
2016/12/01 Javascript
微信小程序之拖拽排序(代码分享)
2017/01/21 Javascript
Bootstrap模态框使用详解
2017/02/15 Javascript
Vue官方文档梳理之全局配置
2017/11/22 Javascript
[02:33]2018 DOTA2亚洲邀请赛回顾视频 再次拾起那些美妙的时刻
2018/04/10 DOTA
python文件和目录操作函数小结
2014/07/11 Python
在Python web中实现验证码图片代码分享
2017/11/09 Python
详解python中asyncio模块
2018/03/03 Python
python书籍信息爬虫实例
2018/03/19 Python
python并发编程多进程之守护进程原理解析
2019/08/20 Python
python爬虫爬取幽默笑话网站
2019/10/24 Python
Python logging日志模块 配置文件方式
2020/07/12 Python
Python无损压缩图片的示例代码
2020/08/06 Python
Python实现区域填充的示例代码
2021/02/03 Python
初中音乐教学反思
2014/01/12 职场文书
入党积极分子介绍信
2014/01/17 职场文书
关于对大人不礼貌的检讨书
2014/09/29 职场文书
升职自荐信怎么写
2015/03/05 职场文书
MySQL 数据丢失排查案例
2021/05/08 MySQL
SpringCloud的JPA连接PostgreSql的教程
2021/06/26 Java/Android