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 表单验证方法(实用)
Apr 28 Javascript
jQuery UI Datepicker length为空或不是对象错误的解决方法
Dec 19 Javascript
jquery $.ajax相关用法分享
Mar 16 Javascript
深入理解javascript动态插入技术
Nov 12 Javascript
jQuery实现渐变弹出层和弹出菜单的方法
Feb 20 Javascript
js实现导航栏中英文切换效果
Jan 16 Javascript
js模拟支付宝密码输入框
Apr 11 Javascript
深入浅析var,let,const的异同点
Aug 07 Javascript
Vue实现底部侧边工具栏的实例代码
Sep 03 Javascript
vue.js实现简单购物车功能
May 30 Javascript
Element中Slider滑块的具体使用
Jul 29 Javascript
js实现前端界面导航栏下拉列表
Aug 27 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站点获取用户IP的安全方法 HTTP_X_FORWARDED_FOR检验
2013/06/01 PHP
基于PHP+Ajax实现表单验证的详解
2013/06/25 PHP
IIS6.0 开启Gzip方法及PHP Gzip函数分享
2014/06/08 PHP
php通过header发送自定义数据方法
2018/01/18 PHP
Yii2框架加载css和js文件的方法分析
2019/05/25 PHP
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
javascript中数组的sort()方法的使用介绍
2013/12/18 Javascript
JavaScript中双叹号(!!)作用示例介绍
2014/04/10 Javascript
使用JavaScript的AngularJS库编写hello world的方法
2015/06/23 Javascript
javascript数组排序汇总
2015/07/07 Javascript
JavaScript 七大技巧(二)
2015/12/13 Javascript
jQuery ajax请求返回list数据动态生成input标签,并把list数据赋值到input标签
2016/03/29 Javascript
animate 实现滑动切换效果【实例代码】
2016/05/05 Javascript
关于webuploader插件使用过程遇到的小问题
2016/11/07 Javascript
Vue通过input筛选数据
2020/10/26 Javascript
基于AngularJS实现的工资计算器实例
2017/06/16 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
2018/09/19 Javascript
Vue2 添加数据可视化支持的方法步骤
2019/01/02 Javascript
解决layui富文本编辑器图片上传无法回显的问题
2019/09/18 Javascript
vue-devtools的安装和使用步骤详解
2019/10/17 Javascript
JavaScript实现单点登录的示例
2020/09/23 Javascript
[01:07]DOTA2次级职业联赛 - Fpb战队宣传片
2014/12/01 DOTA
python MNIST手写识别数据调用API的方法
2018/08/08 Python
利用python如何在前程无忧高效投递简历
2019/05/07 Python
python操作excel让工作自动化
2019/08/09 Python
Python文件操作及内置函数flush原理解析
2020/10/13 Python
在canvas上实现元素图片镜像翻转动画效果的方法
2018/03/20 HTML / CSS
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
BabyBjörn婴儿背带法国官网:BabyBjorn法国
2018/06/16 全球购物
波兰运动鞋网上商店:Distance.pl
2020/07/30 全球购物
高中课前三分钟演讲稿
2014/08/18 职场文书
八年级作文之一起的走过日子
2019/09/17 职场文书
导游词之河北白洋淀
2020/01/15 职场文书
详解PHP Swoole与TCP三次握手
2021/05/27 PHP
MySQL 时间类型的选择
2021/06/05 MySQL
Linux中sftp常用命令整理
2022/06/28 Servers