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

yizhihongxing

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

  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日

相关文章

  • Ant Design封装年份选择组件的方法

    Ant Design是一个流行的UI组件库,它提供了多个常用的组件,但是在特定的业务场景下,我们可能需要定制一些自己的组件,如年份选择组件。在本文中,我们将探讨如何使用Ant Design封装年份选择组件。 第一步:安装Ant Design npm install antd 安装完成后,我们需要在项目中引入Ant Design: import { DateP…

    Vue 2023年5月29日
    00
  • 关于vue-cli 3配置打包优化要点(推荐)

    我来详细讲解一下关于Vue-CLI 3的打包优化要点。 1. 配置文件 Vue-CLI 3的配置文件是通过vue.config.js文件进行配置的。我们可以在这里设置打包的基本配置、压缩代码、CDN等。 2. 代码分割 代码分割是优化打包体积的一个非常重要的方式。一般来说,我们可以通过以下方式进行代码分割: 异步组件:在路由懒加载、组件懒加载的时候使用imp…

    Vue 2023年5月29日
    00
  • vue+iview实现文件上传

    下面是详细讲解”vue+iview实现文件上传”的完整攻略: 准备工作 在项目中安装vue和iview npm install vue iview –save 在main.js中引入vue和iview,并配置相关的组件 import Vue from ‘vue’ import iView from ‘iview’ import ‘iview/dist/st…

    Vue 2023年5月28日
    00
  • vue 中使用print.js导出pdf操作

    下面是详细讲解 “Vue 中使用 print.js 导出 PDF 操作” 的完整攻略: 一、什么是 Print.js Print.js 是一个简单的打印插件,可以让你轻松地打印任何元素。不需要额外的 CSS,只需要调用它的 JavaScript 函数即可。此外,它还支持导出为 PDF 格式。 二、安装 Print.js 你可以使用 npm 或直接在 HTML…

    Vue 2023年5月27日
    00
  • TypeScript在vue中的使用解读

    TypeScript在Vue中的使用解读 为什么要使用TypeScript与Vue一起使用 Vue.js是一款前端开发框架,旨在简化前端开发的复杂性,提高代码的可读性和可维护性。另一方面,TypeScript是一种JavaScript的超集,可以提供编译时类型检查和更好的IDE支持等功能,可以让开发更加容易和稳定。 使用TypeScript和Vue.js一起…

    Vue 2023年5月28日
    00
  • 如何在vue中使用pdfjs预览pdf文件

    下面是“如何在Vue中使用pdf.js预览pdf文件”的完整攻略。 安装pdf.js 首先,我们需要安装pdf.js。可以通过以下命令来安装: npm install pdfjs-dist 使用pdf.js渲染pdf文件 在Vue组件中引入pdf.js和样式文件: import pdfjsLib from ‘pdfjs-dist’; import ‘pdfj…

    Vue 2023年5月28日
    00
  • 改变vue请求过来的数据中的某一项值的方法(详解)

    下面我将详细讲解改变 Vue 组件请求过来的数据中的某一项值的方法。 确定需要修改的数据 首先我们需要确定需要修改的数据,可以通过在 Vue 组件的 mounted 或 created 钩子中打印请求到的数据,查看需要修改的数据具体位置。比如下面这个例子: export default { data() { return { user: null } }, …

    Vue 2023年5月29日
    00
  • 关于Vue中的计算属性和监听属性详解

    关于Vue中的计算属性和监听属性详解 Vue是一个非常流行的前端框架,在Vue的组件中,常常会有需要根据其他数据属性计算出新的属性值供模板渲染的情况。这时候就需要使用Vue提供的计算属性。此外,Vue还提供了监听属性,用于监听数据属性的变化。 计算属性 计算属性的本质就是一个函数,可以接受其他数据属性作为其参数,根据这些参数执行一定的计算逻辑,最终得出一个新…

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