Vue的响应式原理


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        {{message}}
        {{message}}
        {{message}}
    </div>
    <script src="../Vue源码/vue-2.6.14/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el:'#app',
            data(){
                return{
                    message:'哈哈哈'
                }
            }
        })
    </script>
</body>
</html>

vue中数据发生改变,则界面也会发生更新改变。这就是响应式。

1.app.message修改数据时,Vue内部是如何实现监听message发生改变的

vue2采用的是Object.defineProperty进行数据劫持绑定,遍历data中所有对象通过Observer劫持监听所有属性,而vue3则是采用了Proxy对整个对象进行代理,在vue3中,会定义一个响应式函数reactive通过Proxy进行拦截,里面会有get和set方法。进行更改时需要使用.value进行更改

2.当数据发生改变时,Vue如何通知哪些地方进行刷新的。

vue2通过发布订阅者模式来通知页面进行更改数据。

观察者模式(发布-订阅模式)如下:

观察者(订阅者)- Watcher:

update():当事件发生时,具体需要做的事情;

目标(发布者)- Dep:

1.subs数组:用来存储所有的观察者;

2.addSub():用来添加观察者;

3.notify:当事件发生时,调用所有观察者的update()方法;

如下所示:

const obj ={}
    Object.keys(obj).forEach(key =>{
let value = obj[key]
      Object.defineProperty(obj, key,{
get(){
          console.log('试图读取obj的a属性')
},
set(newValue){
          console.log('试图改变obj的a属性')
属性变化时进⾏对
实例进⾏通知
//
Watcher
          dep.notify()
}
})
})
发布者
//
class Dep{
constructor(){
this.subs =[]
}
addSub(watch){
this.subs.push(watch)
}
属性变化发送通知函数
//
notify(){
接受到通知后调⽤
函数进⾏视图的更新
//
update
this.subs.forEach(item =>{
          item.update()
})
}
}
订阅者
//
class Watcher {
constructor(name){
this.name =name
}
update(){
        console.log(this.name+'发⽣update');
}
}
模拟创建⼀个发布者
//
const dep =new Dep()
模拟创建⼀个订阅者
//
const watch1 =new Watcher('第⼀个实例')
将订阅者添加到发布者中
的数组⾥进⾏管理
//
subs
    dep.addSub(watch1)
const watch2 =new Watcher('第⼆个实例')
    dep.addSub(watch2)
const watch3 =new Watcher('第三个实例')
    dep.addSub(watch3)

在其中的过程为:设置一个Observer监听器来对数据(data)中的所有属性进行劫持监听,如果属性发生了变化,则告诉订阅者Watcher看是否需要更新。因为订阅者有多个,所以需要一个消息订阅器(发布者)Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进⾏统⼀管理的。接着,我们还需要有⼀个指令解析器Compile,对每个节点元素进⾏扫描和解析,将相关指令对应初始化成⼀个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执⾏对应的更新函数,从⽽更新视图。

Vue3中的响应式原理

实现原理:

  • 通过Proxy(代理)拦截:拦截对象中任意属性的变化,包括属性的读写,属性的添加,属性的删除等。
  • 通过Reflect(反射):对源对象的属性进行操作。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 
</body>
<script>
    //源数据
    let obj = {
        name:'法外狂徒',
        age:100
    }
 
    // 模拟vue3中的响应式
    //Proxy第一个参数是源数据。第二个参数是配置
    const p = new Proxy(obj,{
        // 读取
        get(target,propName){
            console.log(`读取了p的${propName}属性`)
            return target[propName]
        },
        // 修改,新增
        set(target,propName,value){
            console.log(`修改了p的${propName}属性,准备更新界面`)
            return target[propName] = value
        },
        //删除
        deleteProperty(target,propName){
            console.log(`删除了p的${propName}属性,准备更新界面`)
            return delete target[propName]
        }
    })
</script>
</html>

由此再描述一下Reflect(反射的意思),首先在一个对象obj中,有两个属性a和b,一般情况下读取a属性会使用obj.a来实现。而另一种方式则是使用Reflect.get(obj,a)。

而vue3则正是利用了Reflect实现了数据的响应式。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值