简介
提到vue3对于vue2的改动,proxy代替defineProperty进行依赖的收集派发必定是不得不提的一笔。鉴于proxy在项目中的使用频率不高,线下单独抽时间研究一番。本文完成一个简单的代码执行逻辑,可以执行用户输入的代码,并且提示第n行代码触发了proxy的xx监听事件。并以此分析proxy对于defineProperty的优势。
代码逻辑介绍
先来看看最终的结果
(样式没写,丑的一逼)
执行输入函数
function createExecFunc() {
const formatFunc = `return ${func.value}`
return new Function(formatFunc)()
}
function execFunc() {
const canExecFunc = createExecFunc();
canExecFunc(data, currentLine);
}
直接将代码字符串传入new Function,生成可执行函数。
传入两个参数:
// data中有用于测试的变量
let data = {
definePropObject, // definePropObject增加监听的Object,默认值{}
definePropArray, // definePropObject增加监听的Array,默认值[]
proxyObject, // proxy代理的Object,默认值{}
proxyArray // proxy代理的Array,默认值[]
}
// currentLine为了计算行数,下面讲解
计算行数
增加formatFunc逻辑,在最终执行的函数中增加行数计算逻辑
const formatFunc = `return ${func.value}`
.replace(/\n/g, "\ncurrentLine.num++;\n");
使用currentLine简单的计算行数,执行一行,currentLine++,便可以得到一个基础的行数
(注意:如果出现换行的语句 比如for, while或者对象换行定义等情况,该方法都会失效。所以在这个案例中一个语句或者表达式必须写成一行)
注册代理事件
根据es6.ruanyifeng.com/#docs/proxy和MDN将proxy和defineProperty的监听事件全部注册,在触发时记录事件,并在右侧输出。
以上便完成简单一个可视化的观察proxy监听事件的逻辑。
观察proxy监听事件
下面分析一些proxy的监听事件触发案例。
案例1:对象增加新元素
对于proxy监听的对象,无论你是
插入新属性,对他的自己插入新属性,读取他的属性等操作,都可以被监听到,这一点defineProperty是做不到的。所以vue3不需要有$set操作了。
proxy也只能监听到一级的数据变化,所以在增加新子对象的情况下,还需要对子对象增加对应的proxy作监听
对象2:数组操作
可以发现,对于改变原数组的操作,proxy都可以进行监听的,这一点defineProperty也是做不到的。
所以vue3应该也不需要重写array的相关方法,直接统一处理就行。
这里可能有个疑问,为什么两行代码,触发了这么多个监听事件呢?可以把proxy的回调参数也输出看一下:
可以看到,修改数组长度的操作,数组的length属性也是要触发事件的。splice还会触发proxyt的has,deleteProperty事件。
对象3:其他操作
proxy还有很多可以监听的方法,基本上覆盖了我们平时数据处理的方方面面,可以自己凭兴趣查看
总结
通过上面的操作,可以清楚的归纳一些proxy对于defineProperty的一些优势
- 监听能力远强于defineProperty,不需要$set和对Array的重写。
- 可以惰性监听,在数据初始化的时候只需要监听第一级的数据,在后续操作时再补充依赖。