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 相关文章推荐
在 IE 中调用 javascript 打开 Excel 表
Dec 21 Javascript
JavaScript的原型继承详解
Feb 15 Javascript
jquery不常用方法汇总
Jul 26 Javascript
JS实现超简单的鼠标拖动效果
Nov 02 Javascript
使用 bootstrap modal遇到的问题小结
Nov 09 Javascript
Angular JS 生成动态二维码的方法
Feb 23 Javascript
Bootstrap Table使用整理(五)之分页组合查询
Jun 09 Javascript
vue2利用Bus.js如何实现非父子组件通信详解
Aug 25 Javascript
详解jQuery中的isPlainObject()使用方法
Feb 27 jQuery
微信小程序实现swiper切换卡内嵌滚动条不显示的方法示例
Dec 20 Javascript
详解小程序云开发攻略(解决最棘手的问题)
Sep 30 Javascript
JS图片懒加载技术实现过程解析
Jul 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
php导出word格式数据的代码实例
2013/11/25 PHP
PHP @ at 记号的作用示例介绍
2014/10/10 PHP
php实现微信发红包
2015/12/05 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
Zend Framework使用Zend_Loader组件动态加载文件和类用法详解
2016/12/09 PHP
PHP unlink与rmdir删除目录及目录下所有文件实例代码
2018/02/07 PHP
jquery imgareaselect 使用利用js与程序结合实现图片剪切
2009/07/30 Javascript
Prototype源码浅析 Enumerable部分(二)
2012/01/18 Javascript
extjs 3.31 TreeGrid实现静态页面加载json到TreeGrid里面
2013/04/02 Javascript
jQuery删除节点的三个方法即remove()detach()和empty()
2013/12/27 Javascript
js实现屏幕自适应局部代码分享
2015/01/30 Javascript
JS+CSS实现另类带提示效果的竖向导航菜单
2015/10/15 Javascript
js行号显示的文本框实现效果(兼容多种浏览器 )
2015/10/23 Javascript
原生js获取iframe中dom元素--父子页面相互获取对方dom元素的方法
2016/08/05 Javascript
原生js实现返回顶部缓冲效果
2017/01/18 Javascript
vue表单验证你真的会了吗?vue表单验证(form)validate
2019/04/07 Javascript
基于jquery ajax的多文件上传进度条过程解析
2019/09/11 jQuery
如何使用RoughViz可视化Vue.js中的草绘图表
2021/01/30 Vue.js
Python有序字典简单实现方法示例
2017/09/28 Python
OPENCV去除小连通区域,去除孔洞的实例讲解
2018/06/21 Python
python-pyinstaller、打包后获取路径的实例
2019/06/10 Python
简单的Python调度器Schedule详解
2019/08/30 Python
基于OpenCV的网络实时视频流传输的实现
2020/11/15 Python
欧洲最大的高尔夫零售商:American Golf
2019/09/02 全球购物
Kusmi茶美国官网:优质散叶茶和茶包
2019/10/13 全球购物
给分销商的致歉信
2014/01/14 职场文书
生日寿宴答谢词
2014/01/19 职场文书
户外婚礼策划方案
2014/02/08 职场文书
中学生运动会口号
2014/06/07 职场文书
科级干部群众路线教育实践活动对照检查材料思想汇报
2014/09/20 职场文书
质监局领导班子对照检查材料思想汇报
2014/09/27 职场文书
办理信用卡工作证明
2014/09/30 职场文书
外科护士长工作总结
2015/08/12 职场文书
2016年植树节红领巾广播稿
2015/12/17 职场文书
2019年12月24日平安夜祝福语集锦
2019/12/24 职场文书
CentOS安装Nginx并部署vue
2022/04/12 Servers