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 相关文章推荐
ES6中如何使用Set和WeakSet
Mar 10 Javascript
js实现页面跳转的五种方法推荐
Mar 10 Javascript
浅谈javascript中的Function和Arguments
Aug 30 Javascript
浅谈JS使用[ ]来访问对象属性
Sep 21 Javascript
微信开发 微信授权详解
Oct 21 Javascript
Angular.js实现注册系统的实例详解
Dec 18 Javascript
EasyUI学习之Combobox级联下拉列表(2)
Dec 29 Javascript
jq给页面添加覆盖层遮罩的实例
Feb 16 Javascript
微信小程序 扭蛋抽奖机css3动画实现详解
Jul 19 Javascript
vue 集成jTopo 处理方法
Aug 07 Javascript
swiper4实现移动端导航切换
Oct 16 Javascript
React 条件渲染最佳实践小结(7种)
Sep 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实现邮件群发的源码
2013/06/18 PHP
php实现 master-worker 守护多进程模式的实例代码
2019/07/20 PHP
php解决安全问题的方法实例
2019/09/19 PHP
网页图片延时加载的js代码
2010/04/22 Javascript
基于JavaScript实现继承机制之调用call()与apply()的方法详解
2013/05/07 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
2014/10/16 Javascript
JavaScript中模拟实现jsonp
2015/06/19 Javascript
在Linux系统中搭建Node.js开发环境的简单步骤讲解
2016/01/26 Javascript
bootstrap下拉菜单使用方法解析
2017/01/13 Javascript
angular.fromJson与toJson方法用法示例
2017/05/17 Javascript
Easyui Datagrid自定义按钮列(最后面的操作列)
2017/07/13 Javascript
layui.js实现的表单验证功能示例
2017/11/15 Javascript
JS基于贪心算法解决背包问题示例
2017/11/27 Javascript
微信小程序checkbox组件使用详解
2018/01/31 Javascript
纯JS实现的读取excel文件内容功能示例【支持所有浏览器】
2018/06/23 Javascript
JavaScript函数节流和函数去抖知识点学习
2018/07/31 Javascript
npm的lock机制解析
2019/06/20 Javascript
利用React高阶组件实现一个面包屑导航的示例
2020/08/23 Javascript
解决vue-pdf查看pdf文件及打印乱码的问题
2020/11/04 Javascript
[36:33]2018DOTA2亚洲邀请赛 4.3 突围赛 EG vs Newbee 第二场
2018/04/04 DOTA
Python time模块详解(常用函数实例讲解,非常好)
2014/04/24 Python
Python实现求最大公约数及判断素数的方法
2015/05/26 Python
python3.6的venv模块使用详解
2018/08/01 Python
值得收藏,Python 开发中的高级技巧
2018/11/23 Python
Python matplotlib通过plt.scatter画空心圆标记出特定的点方法
2018/12/13 Python
详解python中init方法和随机数方法
2019/03/13 Python
Django 设置多环境配置文件载入问题
2020/02/25 Python
CSS中几个与换行有关的属性简明总结
2014/04/15 HTML / CSS
详解CSS3的box-shadow属性制作边框阴影效果的方法
2016/05/10 HTML / CSS
HTML5拖拽功能实现的拼图游戏
2018/07/31 HTML / CSS
Stuart Weitzman欧盟:美国奢华鞋履品牌
2017/05/24 全球购物
搞笑爱情保证书
2014/04/29 职场文书
初中学生操行评语
2014/12/26 职场文书
2015年小学图书室工作总结
2015/05/18 职场文书
建党伟业的观后感
2015/06/01 职场文书
公司员工宿舍管理制度
2015/08/07 职场文书