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中文入门指南,翻译加实例,jQuery的起点教程
Feb 09 Javascript
js文件Cookie存取值示例代码
Feb 20 Javascript
JavaScript实现twitter puddles算法实例
Dec 06 Javascript
jQuery左侧大图右侧小图焦点图幻灯切换代码分享
Aug 19 Javascript
js实现文字垂直滚动和鼠标悬停效果
Dec 31 Javascript
Jquery和angularjs获取check框选中的值的方法汇总
Jan 17 Javascript
JS判断字符串变量是否含有某个字串的实现方法
Jun 03 Javascript
浅谈bootstrap源码分析之tab(选项卡)
Jun 06 Javascript
js学习总结之DOM2兼容处理顺序问题的解决方法
Jul 27 Javascript
React 组件间的通信示例
Jun 14 Javascript
微信小程序 生成携带参数的二维码
Oct 23 Javascript
vue将data恢复到初始状态 &amp;&amp; 重新渲染组件实例
Sep 04 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
destoon实现调用热门关键字的方法
2014/07/15 PHP
PHP+jQuery 注册模块的改进(一):验证码存入SESSION
2014/10/14 PHP
PHP+MySQL存储数据常见中文乱码问题小结
2016/06/13 PHP
php设计模式之策略模式实例分析【星际争霸游戏案例】
2020/03/26 PHP
js 无提示关闭浏览器页面的代码
2010/03/09 Javascript
swtich/if...else的替代语句
2015/08/16 Javascript
AngularJS仿苹果滑屏删除控件
2016/01/18 Javascript
jquery form表单获取内容以及绑定数据
2016/02/24 Javascript
jquery输入数字随机抽奖特效的简单实现代码
2016/06/10 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
Vuejs第十三篇之组件——杂项
2016/09/09 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
2016/12/18 Javascript
webuploader模态框ueditor显示问题解决方法
2016/12/27 Javascript
vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】
2018/11/08 Javascript
如何在Vue中使用CleaveJS格式化你的输入内容
2018/12/14 Javascript
详解使用Nuxt.js快速搭建服务端渲染(SSR)应用
2019/03/13 Javascript
JavaScript实现秒杀时钟倒计时
2019/09/29 Javascript
小程序实现上传视频功能
2020/08/18 Javascript
浅析VUE防抖与节流
2020/11/24 Vue.js
Python版的文曲星猜数字游戏代码
2013/09/02 Python
二种python发送邮件实例讲解(python发邮件附件可以使用email模块实现)
2013/12/03 Python
python基础教程之对象和类的实际运用
2014/08/29 Python
Python json模块使用实例
2015/04/11 Python
tensorflow 打印内存中的变量方法
2018/07/30 Python
对python 自定义协议的方法详解
2019/02/13 Python
opencv resize图片为正方形尺寸的实现方法
2019/12/26 Python
python 提高开发效率的5个小技巧
2020/10/19 Python
Html5移动端获奖无缝滚动动画实现示例
2018/06/25 HTML / CSS
Omio意大利:全欧洲低价大巴、火车和航班搜索和比价
2017/12/02 全球购物
27个经典Linux面试题及答案,你知道几个?
2014/03/11 面试题
写演讲稿所需要注意的4个条件
2014/01/09 职场文书
中学生家长评语大全
2014/04/16 职场文书
感恩祖国演讲稿
2014/09/09 职场文书
2014年残疾人工作总结
2014/12/06 职场文书
Python if else条件语句形式详解
2022/03/24 Python