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 居中漂浮广告
Mar 21 Javascript
js实现两个值相加alert出来精确到指定位
Sep 25 Javascript
js加密解密字符串可自定义密码因子
May 13 Javascript
Javascript对象Clone实例分析
Jun 09 Javascript
js仿QQ中对联系人向左滑动、滑出删除按钮的操作
Apr 07 Javascript
详解Vue中使用v-for语句抛出错误的解决方案
May 04 Javascript
分析JS单线程异步io回调的特性
Dec 01 Javascript
js中apply和Math.max()函数的问题及区别介绍
Mar 27 Javascript
vue 中swiper的使用教程
May 22 Javascript
微信小程序实现swiper切换卡内嵌滚动条不显示的方法示例
Dec 20 Javascript
迅速了解一下ES10中Object.fromEntries的用法使用
Mar 05 Javascript
在element-ui的select下拉框加上滚动加载
Apr 18 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通过COM使用ADODB的简单例子
2006/12/31 PHP
FleaPHP的安全设置方法
2008/09/15 PHP
网站防止被刷票的一些思路与方法
2015/01/08 PHP
phpcms实现验证码替换及phpcms实现全站搜索功能教程详解
2017/12/13 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
JavaScript-世界上误解最深的语言分析
2007/08/12 Javascript
原生javascript实现图片滚动、延时加载功能
2015/01/12 Javascript
jquery实现上下左右滑动的方法
2015/02/09 Javascript
jquery实现ajax提交表单信息的简单方法(推荐)
2016/08/24 Javascript
利用yarn实现一个webpack+react种子
2016/10/25 Javascript
Bootstrap Table使用整理(二)
2017/06/09 Javascript
nodejs操作mongodb的增删改查功能实例
2017/11/09 NodeJs
vue router 跳转后回到顶部的实例
2018/08/31 Javascript
JS散列表碰撞处理、开链法、HashTable散列示例
2019/02/08 Javascript
[01:11]回顾历届DOTA2国际邀请赛中国区预选赛
2017/06/26 DOTA
Python压缩和解压缩zip文件
2015/02/14 Python
python 字典修改键(key)的几种方法
2018/08/10 Python
python使用pandas处理excel文件转为csv文件的方法示例
2019/07/18 Python
Python爬虫图片懒加载技术 selenium和PhantomJS解析
2019/09/18 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
Html5页面在微信端的分享的实现方法
2018/08/30 HTML / CSS
美国网上书店:Barnes & Noble
2018/08/15 全球购物
如何估计一张表的大小(假设该表中有1万条数据)
2016/03/27 面试题
自我鉴定写作要点
2014/01/17 职场文书
领导失职检讨书
2014/02/24 职场文书
家教广告词
2014/03/19 职场文书
采购意向书范本
2014/03/31 职场文书
2014年五一劳动节社区活动总结
2014/04/14 职场文书
项目合作协议书
2014/09/23 职场文书
个人三严三实对照检查材料
2014/09/25 职场文书
财务工作检讨书
2014/10/29 职场文书
2015年教师工作总结范文
2015/03/31 职场文书
罗马假日观后感
2015/06/08 职场文书
《一面五星红旗》教学反思
2016/02/23 职场文书
Python 多线程处理任务实例
2021/11/07 Python
MySQL事务的隔离级别详情
2022/07/15 MySQL