vue3.0的proxy响应式原理简单实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3.0的proxy响应式原理简单实现相关的知识,希望对你有一定的参考价值。
参考技术A vue3.0监测机制有了很大的改善,弥补了vue2.0的一些局限:
vue3.0 使用proxy代替了vue2.0版本中的defineProperty,首先利用compositionAPI中的 reactive() 函数返回一个proxy对象,使得数据可监测
target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
baseHandler中定义拦截的get set方法,监测和改写数据,为了方便,我们需要先将所有依赖收集起来,一旦数据发生变化,就统一通知更新。就是典型的“发布订阅者”模式,数据变化为“发布者”,依赖对象为“订阅者”。
Proxy 与Reflect 组合使用,Proxy拦截用户对目标对象的访问, 而实际对数据的操作由Reflect来完成
Reflect对象与Proxy对象一样,是ES6为了操作对象而提供的新API ,Reflect不能执行new指令。
Reflect作用:优化Object的一些操作方法以及合理的返回Object操作返回的结果。
track() 函数用来收集依赖,将所有 get 的 target 跟 key 以及 effect 建立起对应关系,使用一个全局的 WeakMap 类型变量 targetMap 来存储 target,还需要一个全局的数组来存储 effect
trigger() 函数用来通知订阅者,更新数据,执行effect,普通的effect和computed有优先级,effect先执行,computed后执行,因为 computed 可能会依赖普通的 effect
proxy的兼容性不是很好,由于ES5的限制,ES6新增的Proxy无法被转译成ES5,目前可以通过Polyfill提供部分兼容
https://www.npmjs.com/package/proxy-polyfill
https://www.npmjs.com/package/es6-proxy-polyfill
https://github.com/GoogleChrome/proxy-polyfill
敲黑板,划重点!!!Vue3.0响应式实现原理 —— proxy()
1. 先来回顾一下Vue2.0的响应式原理
- 通过 Object.defineProperty() 实现数据劫持
存在的问题
- 针对对象:新增属性,删除属性,界面不更新
- 针对数组:通过下标修改数组,界面不会自动更新
<!DOCTYPE html>
<html>
<head>
<title>模拟vue2.0</title>
</head>
<body>
<input type="text" id="username">
<br>
显示值:<span id="uName"></span>
<script>
var obj = {};
// 模拟双向数据绑定
//Object.defineProperty(obj, prop, descriptor)
//直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
//obj 要在其上定义属性的对象。
//prop 要定义或修改的属性的名称。
//descriptor 将被定义或修改的属性描述符。
Object.defineProperty(obj,"username",{
// Value:"Jack",
get:function(){
console.log("取值");
},
set:function(val){
console.log("设置值");
document.getElementById("uName").innerText=val;
}
});
document.getElementById("username").addEventListener("keyup",function(){
obj.username= event.target.value;
})
//在控制台中输入obj.username会自动触发get方法,输入obj.username="aaa"会自动触发set方法
//此时并没有用事件进行监听,所以修改监听事件里的代码
</script>
</body>
</html>
2. Vue3.0原理实现 —— Proxy()
- 引用数据类型的增删改查统统在行,非常强大
<!DOCTYPE html>
<html>
<head>
<title>vue3响应式</title>
</head>
<body>
<script>
// type="text/javascript"
let obj = {
name: '小明',
age: 18
}
// 1. window内置的
// window.Proxy() => 代理
// obj为源数据
const p = new Proxy(obj, {
// 这里虽然也是get set 但是要比Object.defin()要聪明一些
get(target, propName){
// target 源数据 // b具体属性
// console.log("读取P的属性") // a, b
console.log(`读取P的${propName}属性`)
// return target[propName]
return Reflect.get(target, propName)
},
// 修改+新增都可以捕获
set(target, propName, value){
// console.log("修改了P的属性")
console.log(`修改了P的${propName}属性,值为${value}`)
// 写到这里 还不是响应式 要去修改obj的值
// target[propName] = value
return Reflect.set(target, propName, value)
},
// 加一个删除
deleteProperty(target, propName){
console.log(`删除了P的${propName}属性`)
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
},
})
</script>
</body>
</html>
3. 重点说明 —— Reflect
3.1 Reflect 是用来做什么的?
- 动态对被代理对象的相应属性进行特定的操作(ES6新增)
- 看到上面的代码,你会发现每行Reflect代码上面都注释了一行,实际上不用它,用它上面的代码也可以实现响应式
- 但是Vue3.0 却用的是 Reflect,还是有些深意的
3.2 为什么要用Reflect ?
-
大家可以自行百度,我这里简单说一下(放链接我怕文章发不出去,深感抱歉)
-
简单来说,主要是为了减少源码中的 try catch,如果不使用 Reflect,整个框架需要有大量的 try catch,才能保证在出错的情况下顺利运行,但是源码就会不好维护,看起来不雅观
-
使用Reflect,即使代码出错,可以在抛出错误的同时,让代码正常运行,保证框架的健壮性!
1. 希望本文能对大家有所帮助,如有错误,敬请指出
2. 原创不易,还请各位客官动动发财的小手支持一波(关注、评论、点赞、收藏)
3. 拜谢各位!后续将继续奉献优质好文
4. 如果存在疑问,可以私信我
以上是关于vue3.0的proxy响应式原理简单实现的主要内容,如果未能解决你的问题,请参考以下文章
敲黑板,划重点!!!Vue3.0响应式实现原理 —— proxy()