vue2与vue3的响应式原理

简介: vue2与vue3的响应式原理

vue2

1、对象类型

原理:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
1、定义数据:

const vm = new Vue({
el: '#root',
data: {
    person:{
        name: '张三',
        age: 18
    }
}
})

2、加工数据:为了实现响应式,vue会给data中的每一组key:value都形成了get和set的写法
只要data中的属性发生改变,就会调用set方法,然后重新解析模板,生成虚拟DOM,新旧虚拟DOM对比,更新页面
在这里插入图片描述
3、模拟数据监视:

<script type="text/javascript" >
    let data = {
        name:'张三',
        age:18
    }
    //创建一个监视的实例对象,用于监视data中属性的变化
    const obs = new Observer(data)        
    //准备一个vm实例对象
    let vm = {}
    vm._data = data = obs
    function Observer(obj){
        //汇总对象中所有的属性形成一个数组
        const keys = Object.keys(obj)
        //遍历
        keys.forEach((k)=>{
            Object.defineProperty(this,k,{
                get(){
                    return obj[k]
                },
                set(val){
                    obj[k] = val
                }
            })
        })
    }
</script>

这里只能实现一层监视,如果data中还有嵌套的对象,则无效。vue底层做了无限的递归,能够监视data中所有层次的数据。
4、数据代理:

vm._data = data

5、data中已经写好的属性都匹配会匹配get和set(影响页面),之后通过vm._data.person.sex = '男'这种方法添加的属性,通过delete this.person.name删除属性是没有响应式的,界面不会更新
在这里插入图片描述
6、实现后添加的数据有响应式
语法:Vue.set(target,key,val)

Vue.set(vm._data.person,sex,'男')
// 数据代理 
Vue.set(vm.person,sex,'男')
// 或者通过这种方式
vm.$set(vm.person,sex,'男')

注意:
target不能是Vue实例或者实例的根数据对象

// 报错
Vue.set(vm._data,'leader','领导')
Vue.set(vm,'leader','领导')

2、数组类型

原理:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
1、定义数据:

const vm = new Vue({
    el: '#root',
    data: {
        hobby:['抽烟','喝酒','烫头']
    }
})

2、vue没有为数组里面的某一个元素匹配get、set,如果通过索引去改变值时,数据能改掉,但是Vue监测不到,不会引起页面的更新
在这里插入图片描述
3、通过vue封装过了的修改数组方法:push pop shift unshift splice sort reverse可以实现响应式
这些数组的方法被Vue所管理,里面的这些方法不再是正常Array原型对象上的了,它除了可以正常调用Array原型对象上的这些方法外,还能够重新解析模板等一系列操作。
4、Vue.set(vm.hobby,1,'打台球')也能实现响应式数组修改

vue3

vue3的响应式要通过函数是通过函数来实现的

1、ref函数

1、作用: 定义一个响应式的数据
2、语法: const xxx = ref(initValue)

  • 创建一个包含响应式数据的引用对象
  • JS中操作数据: xxx.value
  • 模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>
  • 备注:接收的数据可以是:基本类型、也可以是对象类型。

2、 reactive函数

1、作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
2、语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)

  • reactive定义的响应式数据是“深层次的”。
  • 如果接收的是数组,通过索引改变的数据也是响应式的

实现原理

1、对于基本类型的数据,响应式依然是靠Object.defineProperty()getset完成的。
2、对于对象类型的数据

  • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
  • 通过Reflect(反射): 对源对象的属性进行操作。
let person = {
    name:'张三',
    age:18
}
const p = new Proxy(person, {
    // 拦截读取属性值
    get (target, propName) {
        console.log(`有人读取了p身上的${propName}属性`)
        // return target[propName]
        return Reflect.get(target, propName)
    },
    // 拦截设置属性值或添加新属性
    set (target, propName, value) {
        console.log(`有人修改了p身上的${propName}属性`)
        // target[propName] = value
        Reflect.set(target,propName,value)
    },
    // 拦截删除属性
    deleteProperty (target, propName) {
        console.log(`有人删除了p身上的${propName}属性`)
        // return delete target[propName]
        return Reflect.deleteProperty(target, propName)
    }
})

3、Object.defineProperty(target,propName,value) 如果对对象追加一个属性重名了,会直接报错(单线程后面的不执行)

Object.defineProperty(obj,'c',{
    get() {
        return 3
    }
})
Object.defineProperty(obj,'c',{
    get() {
        return 4
    }
})

4、Reflect.defineProperty(target,propName,value) 如果对对象追加一个属性重名了,不会报错。对框架封装比较友好,可以用if...else

const x1 = Reflect.defineProperty(obj,'c',{
    get() {
        return 3
    }
})
console.log(x1) // true
const x2 = Reflect.defineProperty(obj,'c',{
    get() {
        return 4
    }
})
console.log(x2) // false
相关文章
|
21天前
|
JavaScript 前端开发 算法
vue渲染页面的原理
vue渲染页面的原理
96 56
|
8天前
|
JavaScript 前端开发 UED
vue2和vue3的响应式原理有何不同?
大家好,我是V哥。本文详细对比了Vue 2与Vue 3的响应式原理:Vue 2基于`Object.defineProperty()`,适合小型项目但存在性能瓶颈;Vue 3采用`Proxy`,大幅优化初始化、更新性能及内存占用,更高效稳定。此外,我建议前端开发者关注鸿蒙趋势,2025年将是国产化替代关键期,推荐《鸿蒙 HarmonyOS 开发之路》卷1助你入行。老项目用Vue 2?不妨升级到Vue 3,提升用户体验!关注V哥爱编程,全栈开发轻松上手。
|
11天前
|
JavaScript 前端开发 算法
高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图
mermaid是一款非常优秀的基于 JavaScript 的图表绘制工具,可渲染 Markdown 启发的文本定义以动态创建和修改图表。非常适合新手学习或者做一些弱交互且自定义要求不高的图表 除了流程图以外,mermaid还支持序列图、类图、状态图、实体关系图等图表可供探索。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
11天前
|
JavaScript 前端开发 API
你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解
onMounted作为vue3中最常用的钩子函数之一,能够灵活、随心应手的使用是每个Vue开发者的必修课,同时根据其不同写法的特性,来选择最合适最有利于维护的写法。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
21天前
|
资源调度 JavaScript 前端开发
Pinia 如何在 Vue 3 项目中进行安装和配置?
Pinia 如何在 Vue 3 项目中进行安装和配置?
|
11天前
|
JavaScript 前端开发 API
管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异
一篇文章同时搞定Vue2和Vue3的侦听器,是不是很棒?不要忘了Vue3中多了一个可选项watchEffect噢。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
1月前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
3月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
177 1
|
11天前
|
数据采集 资源调度 JavaScript
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
|
11天前
|
存储 数据采集 供应链
属性描述符初探——Vue实现数据劫持的基础
属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

热门文章

最新文章