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 相关文章推荐
onclick与listeners的执行先后问题详细解剖
Jan 07 Javascript
Textbox控件注册回车事件及触发按钮提交事件具体实现
Mar 04 Javascript
js模仿hover的具体实现代码
Dec 30 Javascript
JavaScript中的闭包
Feb 24 Javascript
浅谈javascript中的call、apply、bind
Mar 06 Javascript
JQuery Mobile 弹出式登录框的实现方法
May 28 Javascript
JavaScript实现的XML与JSON互转功能详解
Feb 16 Javascript
你可能不知道的JSON.stringify()详解
Aug 17 Javascript
Vue中组件之间数据的传递的示例代码
Sep 08 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
Oct 28 Javascript
jQuery事件多次绑定与解绑问题实例分析
Feb 19 jQuery
vue响应式原理与双向数据的深入解析
Jun 04 Vue.js
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判断页面是否是微信打开的示例(微信打开网页)
2014/04/25 PHP
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
thinkPHP中多维数组的遍历方法
2016/01/09 PHP
php、mysql查询当天,查询本周,查询本月的数据实例(字段是时间戳)
2017/02/04 PHP
Laravel框架路由设置与使用示例
2018/06/12 PHP
JavaScript字符串对象fromCharCode方法入门实例(用于把Unicode值转换为字符串)
2014/10/17 Javascript
js限制input标签中只能输入中文
2015/06/26 Javascript
js实现将选中内容分享到新浪或腾讯微博
2015/12/16 Javascript
基于Three.js插件制作360度全景图
2016/11/29 Javascript
基于BootStrap的前端分页带省略号和上下页效果
2017/05/18 Javascript
JavaScript字符串_动力节点Java学院整理
2017/06/27 Javascript
Vue框架中正确引入JS库的方法介绍
2017/07/30 Javascript
JavaScript实现京东购物放大镜和选项卡效果的方法分析
2018/07/05 Javascript
详解微信小程序-扫一扫 wx.scanCode() 扫码大变身
2019/04/30 Javascript
Python 专题三 字符串的基础知识
2017/03/19 Python
Python语言描述KNN算法与Kd树
2017/12/13 Python
Python使用pymongo模块操作MongoDB的方法示例
2018/07/20 Python
对python中GUI,Label和Button的实例详解
2019/06/27 Python
Pytorch数据拼接与拆分操作实现图解
2020/04/30 Python
Django模板报TemplateDoesNotExist异常(亲测可行)
2020/12/18 Python
Html5实现文件异步上传功能
2017/05/19 HTML / CSS
英国最受欢迎的价格比较网站之一:MoneySuperMarket
2018/12/19 全球购物
斐乐美国官方网站:FILA美国
2019/03/01 全球购物
得到Class的三个过程是什么
2012/08/10 面试题
办公室主任主任岗位责任制
2014/02/11 职场文书
安全生产计划书
2014/05/04 职场文书
如何写求职信
2014/05/24 职场文书
工作作风承诺书
2014/08/30 职场文书
党的群众路线教育实践活动心得体会(乡镇)
2014/11/03 职场文书
学生上课迟到检讨书
2015/01/01 职场文书
2015年新农合工作总结
2015/03/30 职场文书
毕业论文答辩演讲稿
2015/06/23 职场文书
公司周年庆典致辞
2015/07/30 职场文书
python 中的@运算符使用
2021/05/26 Python
pytorch 梯度NAN异常值的解决方案
2021/06/05 Python
MySQL性能指标TPS+QPS+IOPS压测
2022/08/05 MySQL