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中如何优雅的捕获 Promise 异常详解

    在 Vue 中,可以通过 Promise 处理异步操作。当 Promise 中发生异常时,Vue 会抛出一个全局的未捕获异常的错误信息。为了更好的捕获 Promise 异常,我们可以采用一些优雅的方法。 优雅的捕获 Promise 异常 Vue 2.6 后提供了一个全局错误处理器(config.errorHandler),我们可以利用这个处理器进行全局的异常…

    Vue 2023年5月28日
    00
  • vue.js在标签属性中插入变量参数的方法

    在Vue.js中,我们可以使用{{ }}来插入数据,这个特性被称为数据绑定。但在某些情况下,我们想要在标签属性中插入变量,该怎么做呢?下面是详细攻略和示例说明。 使用v-bind指令 在 Vue.js 中,我们可以使用指令 v-bind 来动态地绑定一个或多个属性,这也是在标签属性中插入变量的一种方式。 示例1:动态绑定class属性 <templat…

    Vue 2023年5月27日
    00
  • 手把手教你如何开发属于自己的一款小程序

    “手把手教你如何开发属于自己的一款小程序” 一、准备工作 1. 注册小程序账号 在开发小程序前,首先需要在微信公众平台上注册小程序账号。 2. 安装开发工具 微信官方提供了小程序开发工具,可在官网下载并安装:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 3. 创…

    Vue 2023年5月28日
    00
  • Vue3使用时应避免的10个错误总结

    下面就是关于“Vue3使用时应避免的10个错误总结”的完整攻略。 1. 避免在setup函数之外使用响应式数据 setup函数之外的代码主要是为了定义变量或者引用组件。我们还需要明确的一点就是,setup函数是在组件实例被创建之前被调用的,所以setup函数外部的代码是在它之前执行的。如果你使用了响应式数据去创建变量或者引用组件,就会出现bug。 示例: c…

    Vue 2023年5月29日
    00
  • Vuejs第八篇之Vuejs组件的定义实例解析

    Vuejs第八篇之Vuejs组件的定义实例解析,涉及到Vuejs组件的基础知识及其定义方法,下面我来详细介绍一下。 一、什么是Vuejs组件 组件(Component)是Vuejs中的一个重要概念,它是一种抽象的概念,可以把一个页面拆分成多个独立的、可复用的组件,每个组件有自己的对外接口和内部实现,可以方便地进行维护和拓展。 二、Vuejs组件的定义 Vue…

    Vue 2023年5月28日
    00
  • vue实现集成腾讯TIM即时通讯

    vue实现集成腾讯TIM即时通讯 1. 安装TIM SDK 首先,我们需要在项目中安装TIM SDK,在项目根目录下执行以下命令: npm install tim-js-sdk –save 2. 创建TIM实例 安装完成TIM SDK后,我们需要在项目中创建TIM实例,代码示例如下: import TIM from ‘tim-js-sdk’; const …

    Vue 2023年5月27日
    00
  • vue中使用Axios最佳实践方式

    下面就是关于”vue中使用Axios最佳实践方式”的完整攻略: 确定请求的方式 在使用Axios时,我们需要确定请求的方式,可以使用get、post、put、delete等方式,同一个接口的不同请求方式可以得到不同的数据。如需向后端发起请求,需要在axios对象中添加请求方式,具体操作如下: import axios from ‘axios’ // 设置请求…

    Vue 2023年5月28日
    00
  • Vue3插槽Slot实现原理详解

    下面我将为你详细讲解“Vue3插槽Slot实现原理详解”的完整攻略。 什么是插槽(Slot) 在Vue开发中,有时候我们需要在父组件中定义子组件的模板结构,但是子组件的内容是不确定的。这种情况下,我们可以使用插槽(Slot)来解决问题。 插槽允许我们定义一个承载子组件内容的挂载点,然后在子组件中使用具名插槽(Named Slot)或默认插槽(Default …

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