Vue源码学习defineProperty响应式数据原理实现

针对该主题,我将从以下几个方面进行讲解:

  1. defineProperty的基本概念和用法
  2. Vue中响应式数据的实现原理
  3. Vue源码中defineProperty的具体实现步骤和代码分析
  4. 示例说明响应式数据的使用和实现

defineProperty的基本概念和用法

在 ES5 中引入了 Object.defineProperty() 方法,该方法可以对对象的属性进行拦截,实现一些高级操作,如监听一个属性的变化等。

Object.defineProperty(obj, prop, descriptor)

  • obj:需要定义属性的对象
  • prop:需要定义的属性名
  • descriptor:属性描述符对象

descriptor 具有以下键值:

  1. value:属性值,默认为 undefined
  2. writable:该属性能否修改,默认为 false
  3. enumerable:是否能枚举,默认为 false
  4. configurable:是否能删除属性或重新定义属性,默认为 false
  5. get:访问该属性时需要调用的函数,默认为 undefined
  6. set:修改该属性时需要调用的函数,默认为 undefined

Vue中响应式数据的实现原理

Vue 通过 Object.defineProperty() 方法对数据进行劫持,然后调用函数更新视图。

当 Vue 的数据变化时,会调用 Object.defineProperty() 方法重新设置对象的属性,并在 set 函数中触发 watcher(观察者)更新视图。

Vue源码中defineProperty的具体实现步骤和代码分析

在 Vue 源码中,defineProperty 的实现在文件 src/core/observer/index.js 中:

/**
 * Define a reactive property on an Object.
 */
export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  const dep = new Dep()

  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set 

  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }

  let childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}

实现过程和使用 Object.defineProperty() 类似,但是对 setters 和 getters 做了特殊的处理。

当 get 函数传入了 getter 函数时,get 函数调用 getter 函数获取值,否则返回 val 值,即获取该属性的值。

当 set 函数传入了 setter 函数时,调用 setter 函数设置该属性的值,否则直接设置 val。

在 Vue 中,每个组件都会有一个 vm 实例,即 Vue 的实例。这个实例提供了 data 属性和对应的访问器函数。在初始化时,Vue 会使用 Object.defineProperty() 方法定义 data 的每一个属性,并调用 observe 函数递归监听每一个属性的变化。当数据变化时,触发 setter 函数,更新该属性的值,并触发 watcher。

示例说明响应式数据的使用和实现

接下来,我通过两个示例说明响应式数据的使用和实现。

示例一:直接修改数组

const vm = new Vue({
  data: {
    list: [1, 2, 3]
  }
})

vm.list[0] = 0

console.log(vm.list)

上述示例直接修改了数组中的元素,并没有使用 Vue 提供的数组修饰符。这种方式实现视图的更新会出现问题。

Vue 提供了以下数组修饰符:

  • push()、pop()、shift()、unshift()、splice()、sort()、reverse()

使用数组修饰符能够更新视图,可以修改为以下代码:

// 使用 Vue 修饰符
vm.$set(vm.list, 0, 0)

示例二:添加新属性

const vm = new Vue({
  data: {
    info: {
      name: 'Tom',
      age: 18
    }
  }
})

// 添加新属性
vm.info.gender = 'male'

console.log(vm.info)

上述代码添加了 info 对象中的新属性 gender,并没有使用 Vue 提供的 $set 函数。这种方式实现视图的更新会出现问题。

Vue 提供了以下方法增强对象:

  • $set(object, key, value)
  • $delete(object, key)

使用 $set 函数能够更新视图,可以修改为以下代码:

// 使用 Vue 的 $set 函数
Vue.set(vm.info, 'gender', 'male')

以上是 defineProperty 的响应式数据原理实现的完整攻略,希望能对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue源码学习defineProperty响应式数据原理实现 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • 项目中一键添加husky实现详解

    下面是项目中一键添加Husky实现的完整攻略示例,分为如下几个步骤: 步骤一:初始化项目 首先,我们需要创建一个新项目并初始化它。我们可以通过以下命令创建并初始化一个名为“my-project”的新项目。 mkdir my-project cd my-project npm init -y 这个命令会创建一个名为“my-project”的文件夹,并初始化一个…

    Vue 2023年5月28日
    00
  • vue跳转同一个组件,参数不同,页面接收值只接收一次的解决方法

    针对“vue跳转同一个组件,参数不同,页面接收值只接收一次”的问题,我们可以采用以下两种解决方案: 方案一:使用watch监听$route变化 这种方式需要在组件的created或mounted生命周期中,监听vue-router的$route对象。如下所示: <template> <div> <p>{{ message …

    Vue 2023年5月27日
    00
  • 教你三分钟掌握Vue过滤器filters及时间戳转换

    下面是“教你三分钟掌握Vue过滤器filters及时间戳转换”的完整攻略。 介绍Vue过滤器 在Vue中,过滤器(filters)是一种可以对文本格式进行转换的方法,它们可以用于格式化、排序、搜索等操作。Vue中的过滤器非常灵活,可以在数据被渲染成DOM之前对数据进行处理。下面我将介绍如何使用Vue过滤器对时间戳进行转换。 时间戳转换成日期格式 可以使用Vu…

    Vue 2023年5月29日
    00
  • Vue Axios异步与数据类型转换问题浅析

    下面我将为您详细讲解 “Vue Axios异步与数据类型转换问题浅析” 的完整攻略。 一、背景介绍 Axios 是一个基于 Promise 的 HTTP 库,可以在浏览器和 Node.js 中使用,用于与后台接口进行数据交互。Vue 是一个流行的前端框架,实现了数据的双向绑定和组件化开发,使得前端开发更加高效和灵活。 但在使用 Vue 和 Axios 进行开…

    Vue 2023年5月27日
    00
  • vue-cli脚手架-bulid下的配置文件

    当使用 Vue.js 开发项目时,经常会使用到 Vue CLI 脚手架工具来初始化项目,并在 build 时自动生成配置文件来进行编译、打包等操作。以下是 Vue CLI 脚手架中 bulid 下的配置文件的详细解析: 1. 配置文件的作用 Vue CLI 脚手架的 build 目录下存放的是一些 webpack 的配置文件,这些配置文件主要用于在生产环境下…

    Vue 2023年5月28日
    00
  • Vue报错:TypeError: Cannot create property ‘xxxx‘ on的解决

    当 Vue 报出 “TypeError: Cannot create property ‘xxxx’ on” 类型的错误时,通常是由于在组件中调用了未定义的数据或方法。这种错误的解决方案可能有很多,我们可以从以下几个方面来处理: 检查组件的数据 首先,我们需要检查组件中使用的数据,确保其已在组件中初始化或定义。如果该数据是作为组件属性传入的,则需要确保传入的…

    Vue 2023年5月27日
    00
  • vue动态生成新表单并且添加验证校验规则方式

    如果要在Vue中动态生成新表单并且添加验证校验规则,可以通过以下步骤完成: 安装Vue的表单验证插件Vuelidate。在项目根目录下执行以下命令: npm install vuelidate 在Vue文件中引入Vuelidate import { required } from ‘vuelidate/lib/validators’; export defa…

    Vue 2023年5月27日
    00
  • 浅析Vue实例以及生命周期

    浅析Vue实例以及生命周期 Vue是一种轻量级MVVM框架,它提供的易用性和高可扩展性让它成为前端开发中非常流行的框架。在Vue中,我们通常会首先创建Vue实例,通过Vue实例来操作整个应用程序,并控制各个组件的生命周期。 Vue实例 Vue实例是Vue的核心概念之一,它是用来管理Vue应用程序的一个实例。在创建Vue实例时,我们需要传入一个选项对象,这个选…

    Vue 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部