vue学习之深刻响应式原理

vue的响应式原理html

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

Object.defineProperty 是 ES5 中一个没法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的缘由。设计模式

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

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

 

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

首先我们须要掌握两个方法学习

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

Object.defineProperty方法this

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

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 变为 “哈哈”

相关文章
相关标签/搜索