Vue实例初始化为渲染函数设置检查源码剖析

Vue实例初始化为渲染函数设置检查源码剖析

目录

引言

_renderProxy是干什么的

initProxy方法

总结

引言

之前的文章提到,Vue实例化时_init方法做了很多处理,其中就有这么一段:

if (__DEV__) { initProxy(vm) } else { vm._renderProxy = vm }

在生产模式下,_renderProxy直接指向了Vue实例本身,而在开发环境下调用了initProxy方法,那么它究竟是做什么的呢?

_renderProxy是干什么的

通过对_renderProxy进行全局搜索,我们在src\core\instance\render.ts文件中找到了它:

// 源码文件 src\core\instance\render.ts vnode = render.call(vm._renderProxy, vm.$createElement)

也就是说,_renderProxy是渲染函数render的执行上下文,在生产环境下,执行上下文就是实例本身,而在开发环境下,执行上下文则使用initProxy进行了处理,我们接下来看看它究竟做了什么。

initProxy方法

首先判断了当前环境下Proxy对象是否存在进行了判断:

//源码文件 src\core\instance\proxy.ts const hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy) //... initProxy = function initProxy(vm) { if (hasProxy) { // determine which proxy handler to use const options = vm.$options const handlers = options.render && options.render._withStripped ? getHandler : hasHandler vm._renderProxy = new Proxy(vm, handlers) } else { vm._renderProxy = vm } }

如果Proxy对象不存在,就放弃治疗,上下文仍为原Vue实例。

而如果Proxy对象存在,则进一步去$options里获取_withStripped属性,如果_withStripped存在,则使用getHandler方法来代理Vue实例,如果不存在,就使用hasHandler来代理实例。

关于Proxy对象的用法,我在这篇文章里提过,简单来说,它可以为一个对象设定代理,用以拦截对象的各种方法。

那么,我们进一步看一下,hasHandlergetHandler都做了什么,首先是比较简单的getHandler:

// 源码文件:src\core\instance\proxy.ts const getHandler = { get(target, key) { if (typeof key === 'string' && !(key in target)) { if (key in target.$data) warnReservedPrefix(target, key) else warnNonPresent(target, key) } return target[key] } }

这个方法拦截了Vue实例对象的getter,也就是说,当获取实例的属性时,就会触发这个方法,在这个方法中,对属性值是否在实例中以及是否在实例的$data中进行了检查,如果不存在则发出相应的警告:

// 源码文件:src\core\instance\proxy.ts const warnReservedPrefix = (target, key) => { warn( `Property "${key}" must be accessed with "$data.${key}" because ` + 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + 'prevent conflicts with Vue internals. ' + 'See: https://v2.vuejs.org/v2/api/#data', target ) } const warnNonPresent = (target, key) => { warn( `Property or method "${key}" is not defined on the instance but ` + 'referenced during render. Make sure that this property is reactive, ' + 'either in the data option, or for class-based components, by ' + 'initializing the property. ' + 'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', target ) }

hasHandler则是对实例对象的in操作符进行拦截,也就是拦截以下操作:

属性查询:foo in proxy

继承属性查询:foo in Object.create(proxy)

with 检查: with(proxy) { (foo); }

Reflect.has()

那么做了什么呢:

// 源码文件:src\core\instance\proxy.ts const hasHandler = { has(target, key) { const has = key in target const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)) if (!has && !isAllowed) { if (key in target.$data) warnReservedPrefix(target, key) else warnNonPresent(target, key) } return has || !isAllowed } }

类似的,依然是对属性是否在实例中存在进行了检查,但是多了一步判断,也就是allowedGlobals,它实际上是一个全局方法列表,当模板中出现了里面的方法名后,不会进行下一个步骤的判断,也就不会因为在Vue实例和$options中找不到这个名字的属性而弹出报错,这些方法你在开发过程中肯定都用过:

// 源码文件:src\core\instance\proxy.ts const allowedGlobals = makeMap( 'Infinity,undefined,NaN,isFinite,isNaN,' + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' + 'require' // for Webpack/Browserify ) 总结

Vue实例化过程中,在开发环境下会调用initProxy方法来包装render函数原本的执行上下文(也就是Vue实例本身),在它的getterin操作符中加入一部分属性的检查,当模板中调用的属性不存在于实例中或不存在于$options中时,及时提出警告。

以上就是Vue实例初始化为渲染函数设置检查源码剖析的详细内容,更多关于Vue实例初始化渲染函数检查的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读

    excel怎么用乘法函数

    excel怎么用乘法函数,乘法,函数,哪个,excel乘法函数怎么用?1、首先用鼠标选中要计算的单元格。2、然后选中单元格后点击左上方工具栏的fx公

    excel中乘法函数是什么?

    excel中乘法函数是什么?,乘法,函数,什么,打开表格,在C1单元格中输入“=A1*B1”乘法公式。以此类推到多个单元。1、A1*B1=C1的Excel乘法公式

    标准差excel用什么函数?

    标准差excel用什么函数?,函数,标准,什么,在数据单元格的下方输入l标准差公式函数公式“=STDEVPA(C2:C6)”。按下回车,求出标准公差值。详细

    excel常用函数都有哪些?

    excel常用函数都有哪些?,函数,哪些,常用,1、SUM函数:SUM函数的作用是求和。函数公式为=sum()例如:统计一个单元格区域:=sum(A1:A10)  统计多个

    vue项目一些常见问题

    vue项目一些常见问题,组件,样式,**样式污染问题**同样的样式不需要在每个组件都复制组件内单独的样式加外层class包裹。加scope。否则只是

    01-Vue项目实战-网易云音乐-准备工作

    01-Vue项目实战-网易云音乐-准备工作,网易,项目,前言在接下来的一段时间,我会仿照网易云音乐,利用Vue开发一个移动端的网易云音乐项目。在做

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发,自己的,后台,后台框架一直想开发一套完全属于自己的后台,但是18年的时候,曾经答