vue2.x 对象劫持的原理实现

Vue.js 通过 Object.defineProperty() 函数,对对象的属性进行劫持,实现了数据双向绑定的功能。

具体的实现过程如下:

  1. Vue.js 给每个组件对象(包含 data 属性)都创建了一个 Observer 对象,并将 data 属性的值递归地遍历,使用 Object.defineProperty() 函数将 data 属性的每个属性都转换成 getter/setter。

  2. 在 getter 中,Vue.js 将该属性的 Dep 实例加入到 Watcher 实例的依赖列表中。Dep 实例是一个容器,存储着 Watcher 实例的引用。

  3. 在 setter 中,如果该属性的值发生了变化,则 Vue.js 遍历该属性的 Dep 实例的依赖列表(即 Watcher 实例列表),然后逐个调用依赖项的 update() 方法,更新页面显示的内容。

下面是一个示例说明:

// 定义一个对象
const obj = { a: 1 }

// 使用 Object.defineProperty() 函数实现劫持
Object.defineProperty(obj, 'a', {
  get() {
    console.log('getter')
    return a
  },
  set(val) {
    console.log('setter')
    a = val
  }
})

// 访问属性 a
console.log(obj.a) // 输出 "getter" 和 "1"

// 修改属性 a
obj.a = 2 // 输出 "setter"
console.log(obj.a) // 输出 "getter" 和 "2"

在上面的示例中,当我们读取 obj.a 属性时,会打印出 "getter" 和属性的值 "1"。当我们修改 obj.a 属性时,会打印出 "setter"。这种设置 getter/setter 的方式,就是 Vue.js 实现数据双向绑定的关键所在。

下面是另一个示例,模拟 Vue.js 中的 Watcher 和 Dep 功能:

// 定义一个 Watcher 类
class Watcher {
  constructor() {
    Dep.target = this
  }
  update() {
    console.log('update')
  }
}

// 定义一个 Dep 类
class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  notify() {
    this.subs.forEach(sub => sub.update())
  }
}

// 使用 Watcher 和 Dep 类实现属性劫持
const obj2 = {}
let val2
Object.defineProperty(obj2, 'a', {
  get() {
    console.log('getter')
    Dep.target && Dep.target.addDep(this)
    return val2
  },
  set(val) {
    console.log('setter')
    val2 = val
    this.dep.notify()
  }
})

// 创建 Watcher 实例
const watcher = new Watcher()

// 访问属性 a
obj2.a // 输出 "getter"

// 修改属性 a
obj2.a = 2 // 输出 "setter" 和 "update"

在上面的示例中,我们分别定义了 Watcher 和 Dep 两个类,用来模拟 Vue.js 中的 Watcher 和 Dep 功能。在 getter 中,我们调用了 addDep() 方法,用来将 Watcher 实例添加到 Dep 实例的依赖列表中。在 setter 中,我们调用了 dep.notify() 方法,用来通知依赖该属性的 Watcher 实例执行 update() 方法。最后,创建了一个 Watcher 实例,来监听属性 a 的变化。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue2.x 对象劫持的原理实现 - Python技术站

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

相关文章

  • vue项目页面的打印和下载PDF加loading效果的实现(加水印)

    要实现Vue项目页面的打印和下载PDF加loading效果的实现(加水印),需要按照以下步骤进行: 1. 安装依赖 需要安装以下两个依赖: html2canvas:用于将页面截图并转换为canvas。 jspdf:用于将canvas转成PDF。 可以使用以下命令进行安装: npm install html2canvas jspdf –save 2. 实现打…

    Vue 2023年5月27日
    00
  • Vue element el-table-column中对日期进行格式化方式(全局过滤器)

    针对Vue element el-table-column中对日期进行格式化方式,可以通过全局过滤器来实现,以下是具体步骤。 步骤一:创建全局过滤器 在Vue项目的main.js文件中,定义一个全局过滤器来格式化日期,代码如下: import Vue from ‘vue’; import moment from ‘moment’; Vue.filter(‘f…

    Vue 2023年5月29日
    00
  • 详解Vue的七种传值方式

    详解Vue的七种传值方式 在Vue中,数据传递是开发中不可避免的问题,而Vue又提供了多种传值方式,方便我们进行数据的双向绑定和组件之间的交互。本文将详细介绍Vue的七种传值方式,并通过示例代码让你了解它们的使用方法及各自的优缺点。 父组件向子组件传值 1. props 最常见的方式就是通过props向子组件传值。使用该方式,父组件可以将需要传递的数据作为p…

    Vue 2023年5月28日
    00
  • vue-cli项目中遇到的eslint的坑及解决

    在Vue项目中使用ESLint可以规范代码风格,提高代码质量,但有时会遇到一些ESLint的坑。在vue-cli项目中遇到的ESLint的坑及解决方法如下: 1. VS Code使用ESLint插件无法生效 在VS Code中安装并启用了ESLint插件(如ESLint、Vetur),但并不能如预期般发现编写的代码不符合ESLint规范时提示错误信息或警告信…

    Vue 2023年5月28日
    00
  • vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)

    Vue.js中的自定义指令是一种非常重要的扩展机制,可以实现在标准DOM元素上添加额外的行为,从而实现更加强大的功能。 Vue.js提供了两种自定义指令的实现方法,一种是内部自定义指令,一种是全局自定义指令。下面将详细讲解如何使用Directive实现这两种自定义指令。 内部自定义指令 内部自定义指令是指在Vue.js组件的template中定义的指令,在组…

    Vue 2023年5月28日
    00
  • 关于VueRouter导入的全过程

    VueRouter是Vue.js官方提供的路由管理插件,可以帮助我们快速搭建单页应用,提供了基于Vue.js的路由机制。下面是关于VueRouter导入的全过程的详细攻略: 安装VueRouter 使用Vue.js框架中的VueRouter前,需要先安装VueRouter。在命令行中使用以下命令安装: npm install vue-router –sav…

    Vue 2023年5月28日
    00
  • Vue动态样式方法实例总结

    Vue动态样式方法实例总结 在Vue中,有多种方法可以实现动态修改样式。本文将总结并讲解其中的三种方法。 1. 绑定style 使用:style指令可以将一个样式对象应用到元素上,该样式对象中的属性将会动态地更新: <template> <div :style="{ color: textColor }">这是一个…

    Vue 2023年5月28日
    00
  • TSX常见简单入门用法之Vue3+Vite

    TSX是指将JSX语法与Typescript结合起来使用的技术。TSX通常用于开发React和Vue等现代Web框架。下面我将详细讲解如何使用TSX开发Vue3项目,基于Vite打包工具。整个过程包含以下几步: 安装所需依赖 在开始使用TSX开发Vue3之前,我们需要安装相关的依赖包。在我们的项目中先安装vue和@vue/compiler-sfc两个依赖。 …

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