【Vue】Vue中响应式原理和双向绑定的实现

😁 作者简介:一名大四的学生,致力学习前端开发技术

⭐️个人主页:夜宵饽饽的主页

❔ 系列专栏:Vue小贴士

👐学习格言:成功不是终点,失败也并非末日,最重要的是继续前进的勇气

​🔥​前言:

这里是我整理的关于Vue中双向绑定和响应式原理的理解,还有关于Vue3和Vue2版本响应式的区别,希望可以帮助到大家,欢迎大家的补充和纠正

vue 响应式原理以及双向绑定实现代码 ?

一、 双向绑定

双向绑定可以理解成:

第一向:数据驱动视图,通过getter/setter提前设置数据改变之后的回调来完成

第二向:视图到数据,通过事件驱动,通常涉及的是用户交互

双向绑定的核心就是响应式系统

二、响应式原理:

1)数据劫持

Vue使用名为Observer的类来实现数据劫持,当创建Vue实例时,Vue会遍历传入的数据对象,对其进行遍历递归并使用Object.defineProperty方法将对象的属性转化为"响应式"属性

2)建立依赖追踪关系

在属性转化为响应式属性时,Vue会为每一个属性创建Dep依赖对象,用于收集当前属性的依赖关系

3)依赖收集

当访问一个响应式数据时,Vue会在访问的过程中收集依赖,这是通过在getter方法中进行依赖追踪来实现的,在getter方法中,Vue会判断是否存在Dep对象,如果存在将Dep对象添加到依赖列表中,这样就建立了依赖关系,将属性和对应的Watcher对象关联起来

4)响应更新

当属性发生变化时,Vue会触发属性的setter方法,并通知该属性的Dep对象,然后Dep对象会遍历依赖列表,通知每一个依赖的Watcher对象进行更新操作

这就是响应式原理,也被称为发布订阅

🌱vue2中简单实现的响应式系统

javascript 复制代码
/**
 * 订阅-发布,get订阅,set发布
 */

class Dep{
    constructor(){
        this.subscribers=new Set()
    }

    depend(){
        //判断依赖目标。空时没有意义的
        if(Dep.target){
            this.subscribers.add(Dep.target)
        }
    }

    notify(){
        this.subscribers.forEach(el=>el())
    }
}

Dep.target=null
function defineReactive(obj,key,val){
    const dep=new Dep()

    Object.defineProperty(obj,key,{
        enumerable:true,
        configurable:true,
        get:function reactiveGetter (){
            dep.depend()
            return val
        },
        set:function reactiveSetter (newVal){
            if(newVal===val) return
            val=newVal
            dep.notify()

        }
    })
}


function watcher(fun){
    Dep.target=fun
    fun()
    Dep.target=null
}

let data={age:15,number:3}
defineReactive(data,'age',data.age)
defineReactive(data,'number',data.number)

let total=0

watcher(()=>{
    total=data.age * data.number
})

console.log(total)
data.age=20
console.log(total)

🌱vue3中简单实现的响应式系统

javascript 复制代码
class Dep{
    constructor(){
        this.subscribers=new Set()
    }

    depend(){
        if(Dep.target){
            this.subscribers.add(Dep.target)
        }
    }

    notify(){
        this.subscribers.forEach(el=>el())
    }
}


function definereactive(target){
    const dep=new Dep()

    let handle={
        get(target,key,receiver){
            dep.depend()
            return Reflect.get(target,key,receiver)
        },

        set(target,key,value,receiver){
            if(target[key]===value) return true
            Reflect.set(target,key,value,receiver)
            dep.notify()
        }
    }

    return new Proxy(target,handle)
}

Dep.target=null


function watcher(fun){
    Dep.target=fun
    fun()
    Dep.target=null
}

let data={age:15,number:2}

let proxyData=definereactive(data)

let total=0
watcher(()=>{
    total=proxyData.age * proxyData.number
})

console.log(total)
proxyData.number=4
console.log(total)

总结

⭐Vue3中改用proxy的利弊

放弃了对低版本浏览器的兼容,换来了三点的提升

  1. 对属性的添加和删除动作的监测
  2. 对数组基于下标的修改的监测
  3. 对Map,Set,WeakMap,WeakSet的支持
相关推荐
多云的夏天20 分钟前
前端:VUE-(0)-环境搭建和helloworld
前端·javascript·vue.js
开开心心就好1 小时前
Word图片格式调整与转换工具
java·javascript·spring·eclipse·pdf·word·excel
Stringzhua1 小时前
JavaScript【5】DOM模型
开发语言·javascript·ecmascript
GanGuaGua1 小时前
Vue3:脚手架
前端·javascript·css·vue.js·vue
weixin_431600442 小时前
使用 Vue Tour 封装一个统一的页面引导组件
javascript·vue.js·ecmascript
胡斌附体3 小时前
vue添加loading后修复页面渲染问题
前端·javascript·vue.js·渲染·v-if·异步加载
Dontla3 小时前
Webpack DefinePlugin插件介绍(允许在编译时创建JS全局常量,常量可以在源代码中直接使用)JS环境变量
运维·javascript·webpack
沐土Arvin4 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
咖啡の猫5 小时前
JavaScript基础-创建对象的三种方式
开发语言·javascript·ecmascript
MaCa .BaKa5 小时前
38-日语学习小程序
java·vue.js·spring boot·学习·mysql·小程序·maven