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 相关文章推荐
jquery插件 cluetip 关键词注释
Jan 12 Javascript
jQuery的一些特性和用法整理小结
Jan 13 Javascript
常见JS效果之图片减速度滚动实现代码
Dec 08 Javascript
jQuery异步验证用户名是否存在示例代码
May 21 Javascript
javascript使用avalon绑定实现checkbox全选
May 06 Javascript
javascript实现跨域的方法汇总
Jun 25 Javascript
使用MUI框架模拟手机端的下拉刷新和上拉加载功能
Sep 04 Javascript
Bootstrap Tooltip显示换行和左对齐的解决方案
Oct 11 Javascript
实例讲解v-if和v-show的区别
Jan 31 Javascript
原生JS实现逼真的图片3D旋转效果详解
Feb 16 Javascript
node.js express框架简介与实现
Jul 23 Javascript
JavaScript数组排序小程序实现解析
Jan 13 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
自动跳转中英文页面
2006/10/09 PHP
PHP中数组的三种排序方法分享
2012/05/07 PHP
php中过滤非法字符的具体实现
2013/10/29 PHP
PHP数组操作实例分析【添加,删除,计算,反转,排序,查找等】
2016/12/24 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
如何用js控制frame的隐藏或显示的解决办法
2013/03/20 Javascript
javacript使用break内层跳出外层循环分析
2015/01/12 Javascript
javascript表格的渲染组件
2015/07/03 Javascript
关于input全选反选恶心的异常情况
2016/07/24 Javascript
利用JS实现简单的瀑布流加载图片效果
2017/04/22 Javascript
关于vue.js v-bind 的一些理解和思考
2017/06/06 Javascript
详谈表单格式化插件jquery.serializeJSON
2017/06/23 jQuery
JavaScript动态绑定详解
2017/09/14 Javascript
Vue 2.0入门基础知识之内部指令详解
2017/10/15 Javascript
基于Vue的延迟加载插件vue-view-lazy
2018/05/21 Javascript
Vue路由切换时的左滑和右滑效果示例
2018/05/29 Javascript
JavaScript中为事件指定处理程序的五种方式分析
2018/07/27 Javascript
Vue项目pdf(base64)转图片遇到的问题及解决方法
2018/10/19 Javascript
Vue proxyTable配置多个接口地址,解决跨域的问题
2020/09/11 Javascript
vue通过接口直接下载java生成好的Excel表格案例
2020/10/26 Javascript
[01:43]3.19DOTA2发布会 三代刀塔人第三代
2014/03/25 DOTA
[05:35]DOTA2英雄梦之声_第13期_拉比克
2014/06/21 DOTA
简单分析Python中用fork()函数生成的子进程
2015/05/04 Python
python实现梯度下降算法
2020/03/24 Python
一行代码让 Python 的运行速度提高100倍
2018/10/08 Python
python爬取百度贴吧前1000页内容(requests库面向对象思想实现)
2019/08/10 Python
关于torch.optim的灵活使用详解(包括重写SGD,加上L1正则)
2020/02/20 Python
如何使用pandas读取txt文件中指定的列(有无标题)
2020/03/05 Python
tensorflow常用函数API介绍
2020/04/19 Python
快速了解Python开发环境Spyder
2020/06/29 Python
Python基于爬虫实现全网搜索并下载音乐
2021/02/14 Python
中国京东和泰国中央集团合资的网站:JD CENTRAL
2020/08/22 全球购物
事业单位竞聘上岗实施方案
2014/03/28 职场文书
2014年材料员工作总结
2014/11/19 职场文书
工作表扬信
2015/01/17 职场文书
Nginx访问日志及错误日志参数说明
2021/03/31 Servers