可视化学习proxy方案

81 阅读1分钟

简介

提到vue3对于vue2的改动,proxy代替defineProperty进行依赖的收集派发必定是不得不提的一笔。鉴于proxy在项目中的使用频率不高,线下单独抽时间研究一番。本文完成一个简单的代码执行逻辑,可以执行用户输入的代码,并且提示第n行代码触发了proxy的xx监听事件。并以此分析proxy对于defineProperty的优势。

代码逻辑介绍

先来看看最终的结果

10.gif (样式没写,丑的一逼)

执行输入函数

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:对象增加新元素

image.png 对于proxy监听的对象,无论你是插入新属性对他的自己插入新属性,读取他的属性等操作,都可以被监听到,这一点defineProperty是做不到的。所以vue3不需要有$set操作了。

proxy也只能监听到一级的数据变化,所以在增加新子对象的情况下,还需要对子对象增加对应的proxy作监听

对象2:数组操作

image.png

可以发现,对于改变原数组的操作,proxy都可以进行监听的,这一点defineProperty也是做不到的。

所以vue3应该也不需要重写array的相关方法,直接统一处理就行。

这里可能有个疑问,为什么两行代码,触发了这么多个监听事件呢?可以把proxy的回调参数也输出看一下:

image.png

可以看到,修改数组长度的操作,数组的length属性也是要触发事件的。splice还会触发proxyt的has,deleteProperty事件。

对象3:其他操作

image.png

proxy还有很多可以监听的方法,基本上覆盖了我们平时数据处理的方方面面,可以自己凭兴趣查看

总结

通过上面的操作,可以清楚的归纳一些proxy对于defineProperty的一些优势

  1. 监听能力远强于defineProperty,不需要$set和对Array的重写。
  2. 可以惰性监听,在数据初始化的时候只需要监听第一级的数据,在后续操作时再补充依赖。