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之原型和继承
Jul 06 Javascript
在网站上应该用的30个jQuery插件整理
Nov 03 Javascript
浅析2种JavaScript继承方式
Dec 04 Javascript
jQuery实现进度条效果代码
Dec 17 Javascript
JavaScript实现自动切换图片代码
Oct 11 Javascript
获取本机IP地址的实例(JavaScript / Node.js)
Nov 24 Javascript
微信小程序简单实现form表单获取输入数据功能示例
Nov 30 Javascript
手把手教你用Node.js爬虫爬取网站数据的方法
Jul 05 Javascript
微信小程序第三方框架对比 之 wepy / mpvue / taro
Apr 10 Javascript
JavaScript链式调用原理与实现方法详解
May 16 Javascript
JavaScript实现网页计算器功能
Oct 29 Javascript
vue ref如何获取子组件属性值
Mar 31 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 日,周,月点击排行统计
2012/01/11 PHP
PHP实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
PHP学习记录之常用的魔术常量详解
2019/12/12 PHP
彪哥1.1(智能表格)提供下载
2006/09/07 Javascript
经常用的图片在容器中的水平垂直居中实例
2007/06/10 Javascript
js 多种变量定义(对象直接量,数组直接量和函数直接量)
2010/05/24 Javascript
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
html a标签-超链接中confirm方法使用介绍
2013/01/04 Javascript
jquery简单的拖动效果实现原理及示例
2013/07/26 Javascript
js 文本滚动效果的实例代码
2013/08/17 Javascript
基于jquery扩展漂亮的CheckBox(自己编写)
2013/11/19 Javascript
jQuery获取Radio,CheckBox选择的Value值(示例代码)
2013/12/12 Javascript
Javascript 按位与赋值运算符 (&amp;=)使用介绍
2014/02/04 Javascript
jQuery如何取id有.的值一般的方法是取不到的
2014/04/18 Javascript
jQuery中val()方法用法实例
2014/12/25 Javascript
jQuery实现感应鼠标动画效果自动伸长的输入框实例
2015/02/24 Javascript
JS+CSS实现仿雅虎另类滑动门切换效果
2015/10/13 Javascript
封装属于自己的JS组件
2016/01/27 Javascript
jQuery移动端日期(datedropper)和时间(timedropper)选择器附源码下载
2016/04/19 Javascript
Windows环境下npm install 报错: operation not permitted, rename的解决方法
2016/09/26 Javascript
Javascript 使用ajax与C#获取文件大小实例详解
2017/01/13 Javascript
详解Vue快速零配置的打包工具——parcel
2018/01/16 Javascript
ES6 fetch函数与后台交互实现
2018/11/14 Javascript
vue添加class样式实例讲解
2019/02/12 Javascript
vue中实现回车键登录功能
2020/02/19 Javascript
js实现简单商品筛选功能
2021/02/02 Javascript
go和python变量赋值遇到的一个问题
2017/08/31 Python
Python3.5 处理文本txt,删除不需要的行方法
2018/12/10 Python
人工神经网络算法知识点总结
2019/06/11 Python
使用NumPy读取MNIST数据的实现代码示例
2019/11/20 Python
python getopt模块使用实例解析
2019/12/18 Python
django xadmin action兼容自定义model权限教程
2020/03/30 Python
Python爬虫如何应对Cloudflare邮箱加密
2020/06/24 Python
优秀教师先进个人事迹材料
2014/08/31 职场文书
2015秋季开学典礼新闻稿
2015/07/17 职场文书
2016党员学习《反对自由主义》心得体会
2016/01/22 职场文书