浅谈Vue2.0响应式原理

Vue中,响应式是指数据与视图之间建立一种自动关联的关系,当数据发生变化时,视图会自动更新以反应数据的变化,无需开发者手动操作DOM元素更新视图。

响应式是实现数据驱动视图的基础,在Vue中,数据可以理解为状态state,视图就是用户直观看到的页面UI。页面会随着状态的改变而动态变化,因此可以得到以下公式:

UI = render(state)

上述公式中:状态state是输入,页面UI输出,状态输入一旦变化了,页面输出也随之而变化。这种特性就叫数据驱动视图

公式可以进一步拆成三部分:staterender()以及UI。其中stateUI都是用户定的或开发者实现的,而不变的是render()函数。所以Vue就扮演了render()这个渲染的角色,当Vue检测到state变化之后,经过一系列加工,最终将变化响应式地反应在UI界面上。

实现数据的响应式需要解决以下三个问题:

  1. 如何对状态state的变化进行监听?
  2. 如何确定状态state改变之后要更新的视图?
  3. 更新视图的时机是什么时候?

1. 状态state的变化监听

Vue2中,数据监听是借助了javaScript提供的Object.defineProperty()函数实现的。

1. Object.defineProperty()

Object.defineProperty()静态方法用于在一个对象上定义一个新属性或修改该对象的现有属性。

Object.defineProperty(obj, prop, descriptor)

其中, descriptor表示要定义的属性描述符object,存在两种类型:数据描述符访问器描述符

注意: 描述符只能是这两种类型之一,且两者不能混合使用。

  • 数据描述符是一个具有可写或不可写值的属性,对象支持四种键值:valueenumerablewritableconfigurable

    const person = {
         }
    Object.defineProperty(person, 'age', {
         
      value: 18, // 定义属性值,默认undefined
      enumerable: true, // 属性可枚举, 默认false
      writable: true, // 属性值可修改, 默认false
      configurable: true, // 属性可删除,默认false
    })
    
    console.log(person.age) // > 18
    person.age = 19
    console.log(person.age) // > 19
    
  • 访问器描述符是由 getter/setter 函数对描述的属性,支持四种键值:enumerableconfigurablegetset

    const person = {
         }
    let age = 18
    Object.defineProperty(person, 'age', {
         
      enumerable: true,
      configurable: true,
      get() {
         
        console.log(`有人读取了person的年龄,当前年龄${
           age}`)
        return age
      },
      set(value) {
         
        console.log(`有人修改的person的年龄,新的年龄是${
           value}`)
        age = value
      },
    })
    
    person.age
    person.age = 19
    age
    

输出结果:

1

2. Vue2.0中Object的变化监听

Vue2.0就是利用了Object.defineProperty方法中的访问器描述符来劫持数据的读写操作。在getter中捕获数据的读取事件,在setter中捕获数据的修改事件,进而对数据的变化进行监听。

对于Object类型的数据,Vue通过递归遍历的方式将数据中的每一个属性设置为getter/setter的形式,使对象的每一个属性都变得可观测

👉接下来是对Object类型数据监听的简单实现

  • 模拟一个更新视图的函数

    /**
     * @description: 更新视图函数
     */
    function updateView() {
         
      console.log('收到通知,我去更新视图了')
    }
    
  • 定义Observer

    vue中,所有的响应式数据都是Observer类的实例对象。

    /**
     * @description: 定义Observer类,把一个对象的所有属性转化成可观测对象
     * @return {*}
     */
    class Observer {
         
      constructor(value) {
         
        this.value = value
        // 给value新增一个__ob__属性,值为该value的Observer实例
        // 相当于为value打上标记,表示它已经被转化成响应式了,避免重复操作
        Object.defineProperty(value, '__ob__', {
         
          value: this, 
          enumerable: false,
          writable: true,
          configurable: true,
        })
        this.walk(value)
      }
      walk(value) {
         
        const keys = Object.keys(value)
        for (let i = 0; i < keys.length; i++) {
         
          defineReactive(value, keys[i]) // 遍历所有的属性,将所有属性值转为getter/setter形式
        }
      }
    }
    
  • 定义响应式函数

    // 源码位置:/src/core/observer/index.ts
    /**
     * @description: 给对象的属性递归定义响应式,设置getter/setter,使对象属性的读取事件可监听
     */
    function defineReactive(obj, key, value) {
         
      if (arguments.length === 2) {
         
        value =
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值