文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

引言

之前的文章提到,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操作符进行拦截,也就是拦截以下操作:

那么做了什么呢:

// 源码文件: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实例初始化渲染函数检查的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯