本文最后更新于28 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
在分析Vue3数据响应式的实现前,我们需要先搞清两个概念:副作用函数、响应式数据。
什么是副作用函数?
副作用函数,顾名思义,会产生副作用的函数被称为副作用函数。那么什么是副作用呢?如果一个函数的运行,可能会影响到其他函数或变量,那么这种影响就是一种副作用。我们来看两个例子:
function changeText(text) {
document.body.innerText = text
}
function getText() {
return document.body.innerText
}
changeText函数会修改body的内容。getText会返回body的内容。如果我们使用changeText修改了body内容,那么会影响到getText获取内容,那么这时changeText就是个副作用函数。
副作用函数不一定非要对某些函数产生副作用,如果一个函数修改了全局变量,这其实也是个副作用函数,比如下面的代码:
var flag = true
function changeFlag() {
flag = !flag
}
changeFlag函数会更改一个全局变量flag,那么这也是一种副作用,所以changeText也是个副作用函数。
什么是响应式数据?
所谓的响应式数据就是说,当数据发生改变的时候,视图会自动重新渲染,匹配更新为最新的值。
vue2的响应式数据式是基于ES5的Object.defineProperty实现的,而vue3的响应式数据是基于ES6的Proxy来实现的,Proxy响应式的原理是定义一个Proxy对象来拦截数据读取值和设置值的操作,当读取值的时候把更新页面数据的副作用函数放到一个集合里面,当设置值的时候再从集合中把这个副作用函数取出来并执行这个函数,这样就会把页面更新成修改以后的值。
了解了什么是副作用函数和响应式数据之后,下面我们来模拟Vue3,基于Proxy来实现一个非常基本的数据响应的功能。
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<script type="text/javascript">
//定义一个Set用于保存副作用函数
const bucket=new Set();
//定义一个数据对象
const data={text:'hello world'};
//定义一个副作用函数修改body显示的文本
function effect(){
document.body.innerText=obj.text;
}
//定义一个Proxy对象 用于拦截读取和获取数据的操作
const obj=new Proxy(data,{
//拦截读取操作
get(target,key){
bucket.add(effect);
return target(key);
},
//拦截修改操作
set(target,key,newVal){
target[key]=newVal;
bucket.forEach(fn=>fn());
return true;
}
});
//运行副作用函数
effect();
//设置定时器 一秒钟以后修改body的文本为hello vue2
setTimeout(()=>{
obj.text="hello vue2";
},1000);
</script>
</head>
<body>
</body>
</html>
运行效果: