Vue 2.x 中响应式原理是如何实现的?

2026-05-05 18:141阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计980个文字,预计阅读时间需要4分钟。

Vue 2.x 中响应式原理是如何实现的?

前期准备工作 + 数据驱动 + 响应式核心原理 + 发布订阅者模式与观察者模式 + 数据驱动 + 数据响应式 + 数据模型仅为常见的 + JavaScript 对象,而当我们修改数据时,视图会自动更新,避免了繁琐的操作。

前期准备工作
  1. 数据驱动
  2. 响应式的核心原理
  3. 发布订阅者模式和观察者模式
数据驱动
  • 数据响应式
    • 数据模型仅仅是普通的 JavaScript 对象,而当我们修改数据时,视图会进行更新,避免了繁琐的 DOM 操作,提高开发效率
  • 双向绑定
    • 数据改变,视图改变;视图改变,数据也随之改变
    • 我们可以使用 v-model 在表单元素上创建双向数据绑定
  • 数据驱动是 Vue 最独特的特性之一
    • 开发过程仅需要关注数据本身,不需要关心数据是如何渲染到视图
Vue 2.x 简单响应式例子

主要是利用 ES5 Object.defineProperty,看代码

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello' } // 模拟 Vue 的实例 let vm = {} // 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作 Object.defineProperty(vm, 'msg', { // 可枚举(可遍历) enumerable: true, // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义) configurable: true, // 当获取值的时候执行 get() { console.log('get: ', data.msg) return data.msg }, // 当设置值的时候执行 set(newValue) { console.log('set: ', newValue) if (newValue === data.msg) { return } data.msg = newValue // 数据更改,更新 DOM 的值 document.querySelector('#app').textContent = data.msg } })

肯定会有多个属性,所以只需要循环遍历一下 key

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello', name: 'zhang' } // 模拟 Vue 的实例 let vm = {} proxyData(data) function proxyData(data) { // 遍历 data 对象中的所有属性 Object.keys(data).forEach((key) => { // 把 data 中的属性,转换成 vm 的 setter/setter Object.defineProperty(vm, key, { enumerable: true, configurable: true, get() { console.log('get: ', key, data[key]) return data[key] }, set(newValue) { console.log('set: ', newValue) if (newValue === data[key]) { return } data[key] = newValue // 数据更改,更新 DOM 的值 document.querySelector('#app').textContent = data[key] } }) }) } Vue 3.x 简单响应式例子

主要是 ES6 Proxy,直接监听对象,而非属性

Vue 2.x 中响应式原理是如何实现的?

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello', count: 0 } // 模拟 Vue 实例 let vm = new Proxy(data, { // 当访问 vm 的成员会执行 get(target, key) { console.log('get, key: ', key, target[key]) return target[key] }, // 当设置 vm 的成员会执行 set(target, key, newValue) { console.log('set, key: ', key, newValue) if (target[key] === newValue) return target[key] = newValue document.querySelector('#app').textContent = target[key] } }) 发布/订阅模式

主要是发布者、订阅者、消息中心

class EventEmitter { constructor() { // { eventType: [ handler1, handler2 ] } this.subs = {} } // 订阅通知 $on(eventType, handler) { this.subs[eventType] = this.subs[eventType] || [] this.subs[eventType].push(handler) } // 发布通知 $emit(eventType) { if (this.subs[eventType]) { this.subs[eventType].forEach((handler) => { handler() }) } } } // 测试 var bus = new EventEmitter() // 注册事件 bus.$on('click', function () { console.log('click') }) bus.$on('click', function () { console.log('click1') }) // 触发事件 bus.$emit('click') 观察者

  • 观察者(订阅者) -- Watcher
    • update(): 当事件发生时,具体要做的事
  • 目标(发布者) -- Dep
    • subs 数组:存储所有的观察者
    • addSub():添加观察者
    • notify():当事件发生,调用所有观察者的 update() 方法

// 发布者-目标 class Dep { constructor () { // 记录所有的订阅者 this.subs = [] } // 添加订阅者 addSub (sub) { if(sub && sub.update) { this.subs.push(sub) } } // 发布通知 notify () { this.subs.forEach(sub => { sub.update() }) } } // 订阅者-观察者 class Watcher { update () { console.log('update') } } // 测试 let dep = new Dep() let watcher = new Watcher() dep.addSub(watcher) dep.notify()

来到第二步

本文共计980个文字,预计阅读时间需要4分钟。

Vue 2.x 中响应式原理是如何实现的?

前期准备工作 + 数据驱动 + 响应式核心原理 + 发布订阅者模式与观察者模式 + 数据驱动 + 数据响应式 + 数据模型仅为常见的 + JavaScript 对象,而当我们修改数据时,视图会自动更新,避免了繁琐的操作。

前期准备工作
  1. 数据驱动
  2. 响应式的核心原理
  3. 发布订阅者模式和观察者模式
数据驱动
  • 数据响应式
    • 数据模型仅仅是普通的 JavaScript 对象,而当我们修改数据时,视图会进行更新,避免了繁琐的 DOM 操作,提高开发效率
  • 双向绑定
    • 数据改变,视图改变;视图改变,数据也随之改变
    • 我们可以使用 v-model 在表单元素上创建双向数据绑定
  • 数据驱动是 Vue 最独特的特性之一
    • 开发过程仅需要关注数据本身,不需要关心数据是如何渲染到视图
Vue 2.x 简单响应式例子

主要是利用 ES5 Object.defineProperty,看代码

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello' } // 模拟 Vue 的实例 let vm = {} // 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作 Object.defineProperty(vm, 'msg', { // 可枚举(可遍历) enumerable: true, // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义) configurable: true, // 当获取值的时候执行 get() { console.log('get: ', data.msg) return data.msg }, // 当设置值的时候执行 set(newValue) { console.log('set: ', newValue) if (newValue === data.msg) { return } data.msg = newValue // 数据更改,更新 DOM 的值 document.querySelector('#app').textContent = data.msg } })

肯定会有多个属性,所以只需要循环遍历一下 key

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello', name: 'zhang' } // 模拟 Vue 的实例 let vm = {} proxyData(data) function proxyData(data) { // 遍历 data 对象中的所有属性 Object.keys(data).forEach((key) => { // 把 data 中的属性,转换成 vm 的 setter/setter Object.defineProperty(vm, key, { enumerable: true, configurable: true, get() { console.log('get: ', key, data[key]) return data[key] }, set(newValue) { console.log('set: ', newValue) if (newValue === data[key]) { return } data[key] = newValue // 数据更改,更新 DOM 的值 document.querySelector('#app').textContent = data[key] } }) }) } Vue 3.x 简单响应式例子

主要是 ES6 Proxy,直接监听对象,而非属性

Vue 2.x 中响应式原理是如何实现的?

// 模拟 Vue 中的 data 选项 let data = { msg: 'hello', count: 0 } // 模拟 Vue 实例 let vm = new Proxy(data, { // 当访问 vm 的成员会执行 get(target, key) { console.log('get, key: ', key, target[key]) return target[key] }, // 当设置 vm 的成员会执行 set(target, key, newValue) { console.log('set, key: ', key, newValue) if (target[key] === newValue) return target[key] = newValue document.querySelector('#app').textContent = target[key] } }) 发布/订阅模式

主要是发布者、订阅者、消息中心

class EventEmitter { constructor() { // { eventType: [ handler1, handler2 ] } this.subs = {} } // 订阅通知 $on(eventType, handler) { this.subs[eventType] = this.subs[eventType] || [] this.subs[eventType].push(handler) } // 发布通知 $emit(eventType) { if (this.subs[eventType]) { this.subs[eventType].forEach((handler) => { handler() }) } } } // 测试 var bus = new EventEmitter() // 注册事件 bus.$on('click', function () { console.log('click') }) bus.$on('click', function () { console.log('click1') }) // 触发事件 bus.$emit('click') 观察者

  • 观察者(订阅者) -- Watcher
    • update(): 当事件发生时,具体要做的事
  • 目标(发布者) -- Dep
    • subs 数组:存储所有的观察者
    • addSub():添加观察者
    • notify():当事件发生,调用所有观察者的 update() 方法

// 发布者-目标 class Dep { constructor () { // 记录所有的订阅者 this.subs = [] } // 添加订阅者 addSub (sub) { if(sub && sub.update) { this.subs.push(sub) } } // 发布通知 notify () { this.subs.forEach(sub => { sub.update() }) } } // 订阅者-观察者 class Watcher { update () { console.log('update') } } // 测试 let dep = new Dep() let watcher = new Watcher() dep.addSub(watcher) dep.notify()

来到第二步