当前位置: 首页 > news >正文

vue学习之深入响应式原理

vue的响应式原理

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用  Object.defineProperty 把这些属性全部转为  getter/setter 。

’ Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。每个组件实例都对应一个 watcher 实例,它会在组件

渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

通过这么长时间的学习,我用比较直白的话来详细的解释一下原理

首先咱们需要掌握两个方法

一个是Object.defineProperty,一个是订阅者设计模式

Object.defineProperty方法

Object.defineProperty会直接在一个对象上定义一个新属性或者修改一个对象的现有属性,并且返回这个对象。

Object.defineProperty(obj,prop,descriptor)有三个属性。obj是要定义属性的对象。prop是需要定义或者修改的属性的名称,descrptor是被定义或修改的属性描述符。

setter或者getter是js对象中用来设置属性或获取属性的方法,他是在创建对象的时候指明的。

当data对象中有值存在时,vue就会获取这个对象,获取这个对象的时候就会调用get,然后会用Object.keys()方法拿到这个data对象中的每个属性,

然后进行遍历,得到每个属性,然后通过Object.defineProperty的set和get方法进行设置属性值或者是获取属性值。

发布-订阅模式

举个例子来说明一下发布者订阅者模式。上面的例子中,就是让张三和李四来订阅了这个message属性的改变。

发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而

是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,

只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。

A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。

vue就是通过这种发布者订阅者模式来处理响应式数据的。

下面的代码只是把整个响应式的过程解释了一下,但是源码并不是这么写的,但是整个流程是这样走滴,只不过我简化可很多~~希望大家能明白哈

  // 他们全用了message
  <div>{{message}}</div>
    <p>{{message}}</p>
    <i>{{message}}</i>
 


   data() {
      return {

      message:'嘻嘻',
        name:'why'
    }
 
    },       
 
       // data传进了new Vue里面。内部拿到了data'中的对象,嗯,就拿这个名字命名为obj把,        
       var obj={            
        message:'哈哈',      
          name:'why'          };



// 然后通过遍历obj这个对象拿到这个属性------
      // Object.keys(obj)返回的是一个数组形式的这个对象的属性
          // key代表的是每个属性
          Object.keys(obj).forEach(key => {
            // 拿到这个属性
            let value=obj[key]
            Object.defineProperty(obj,key,{
        // 设置属性
              set(newValue) {
                // 可以在这个位置监听key的改变
                  value=newValue  
        // dep.notify() 然后在类似这个地方通知订阅者发生改变

          <!--  发生改变的时候,需要获取到谁在用这个值,假如这里有俩个人在用张三和李四,此时就需要对每个用到message进行解析,
          根据解析html代码,来获取到哪些人在用这些属性,他在获取message里的
          值的时候,他会调用一下get方法,谁用这个message,谁都会调取一次get,到时候就能知道到底是谁调用了这个message,
          一旦newValue发生改变,就会通知这三个人,然后会通知这三个人,让这三个人把界面更新一下  get方法---自身的update方法
          这时候就需要用发布订阅者模式来监听,让这三个人订阅这个属性的改变-->

                  console.log('监听'+key+'改变'+':'+value)
              },
              get() {

            在类似这个的地方创建一个watch的对象。来获取每个订阅者
            // const wat1=new Watcher('涵涵');
             console.log('获取'+key+'对应的值')

            return value
              }
            })
          })
        // 他就会执行对象里的set属性,把他的名字设置成'hanhan'
        obj.name='hanhan'

我们把多个订阅者对象添加到发布者里面,一旦值发生改变,发布者只要去调用了自己的notify,就会立马通知之前 所有的订阅者,

订阅者是一个数组,遍历数组里的每个成员,数组里面每个成员都有watch,通知订阅者去更新自己的update。然后进行更新界面

          // 发布者
          class Dep {
              constructor() {
                // 订阅了一个数组,用这个数组去记录所有的订阅者
                this.subscription=[]
              }
              // 加入订阅者,加进去这个人,也就是张三李四,这两个人
              addSub(watch) {
                this.subscription.push(watch)
              };
              notify() {
                this.subscription.forEach(item=>{
                  // 调用它自己的unpate去更新
                  item.update()
                })
              }
          }

          // 观察者,用于监听观察,通过这个类创建对象,
          // 订阅者
          class Watcher {
            constructor(name) {
              this.name=name;
            }

            update() {
              // 把自己的内容进行更新
              console.log(this.name+'发生update')
            }
          }

          // 实例一个dep对象
          const dep=new Dep();

          const wat1=new Watcher('张三');
          dep.addSub(wat1)  //张三就被订阅者放到了subscription的数组里面

          const wat2=new Watcher('李四');
          dep.addSub(wat1)  //李四就被订阅者放到了subscription的数组里面

          dep.notify()//这里定义notify,那么刚才的两个订阅者,就全被我通知到了
        }
        



下面我用一张图对上面的内容进行一个总结吧,总结的比较肤浅,都是表面的知识,希望大家多多指点,一块进步哈。

observer主要是对data对象中的数据进行了劫持监听,利用Object.defineProperty,一个属性对应一个dep对象,name有一个dep对象,age有一个dep对象,

他们是一一对应的关系,每个dep对象里面都 有他的观察者对象,观察者1,观察者2...当属性值发生变化的时候就会去调用dep中的notify,通知watcher,利用watcher去更新视图。

当el传进complie里面时,主要是做了两件事

一是解析html,创建对应的watcher,放到对应的observer中的dep对象中去,具体怎么放得,上面有说哈,

二是他还会根据el中的内容初始化view,也就是解析咱们的{{message}}, 在界面中显示出  “ 嘻嘻 ”。

假如我们把name中的属性值改成了 '哈哈 ',那么observer中的Object.defineProperty立马会监听到值的改变,调用notify的方法,遍历watcher,进行update,然后更新视图,把 why 变为 “哈哈”

相关文章:

  • 使用proxy实现一个双向绑定
  • 最全的 Vue 性能优化指南,经典收藏
  • web前端开发不可不知的十个小妙招,让工作更有效率,快收藏吧
  • 翻译:原型继承是如何工作的
  • 35岁并不是程序员的坎,只是你没有真的认清事实
  • Web安全的重要性(面试必备),被黑无数次还不怕吗?
  • 学前端,css与javascript是重难点,基础不好一切白费!
  • Web前端开发应该必备的编码原则
  • vue全家桶开发 去哪儿 项目总结
  • 这「五类人」最适合转Web前端,必须要了解的前端工程师
  • 每周分享,前端自学「书籍推荐」
  • 「程序员之路」年轻,总得做些什么吧(致那些还未定型的程序员)
  • 自学入门,省去几万学费,web前端必须要知道的「基础知识」
  • 身为前端,你不得不懂的一些HTTP知识(附赠3道面试题)
  • web前端30个项目列表,学完即可上手做项目
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 07.Android之多媒体问题
  • 0x05 Python数据分析,Anaconda八斩刀
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • Angular2开发踩坑系列-生产环境编译
  • Java深入 - 深入理解Java集合
  • jquery ajax学习笔记
  • jquery cookie
  • JS字符串转数字方法总结
  • Just for fun——迅速写完快速排序
  • Leetcode 27 Remove Element
  • ng6--错误信息小结(持续更新)
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 订阅Forge Viewer所有的事件
  • 让你的分享飞起来——极光推出社会化分享组件
  • 十年未变!安全,谁之责?(下)
  • 实战|智能家居行业移动应用性能分析
  • 手写双向链表LinkedList的几个常用功能
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 最近的计划
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • #pragma multi_compile #pragma shader_feature
  • ()、[]、{}、(())、[[]]命令替换
  • (03)光刻——半导体电路的绘制
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (Java)【深基9.例1】选举学生会
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (三)终结任务
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • ******IT公司面试题汇总+优秀技术博客汇总
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET MVC第三章、三种传值方式
  • .Net的DataSet直接与SQL2005交互