作用:主要作用是在实例上挂载一个 _renderProxy 指向 vm 实例自身, 这个代理的作用就是为了在开发阶段给我们一个友好而准确的提示
    条件:当且仅当当前环境属于 非生产环境 并且支持 Proxy 的时候 拿取实例中不存在的值的时候会报错
    场景:主要的使用场景是在 render 的时候会通过 _renderProxy 来获取实例中的内容,在上述条件中,如果获取的是不存在或者保留字符则会报错。

    1. // core/isntance/init.js
    2. if (process.env.NODE_ENV !== 'production') {
    3. initProxy(vm)
    4. } else {
    5. vm._renderProxy = vm
    6. }
    1. let initProxy
    2. if (process.env.NODE_ENV !== 'production') {
    3. const allowedGlobals = makeMap(
    4. 'Infinity,undefined,NaN,isFinite,isNaN,' +
    5. 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
    6. 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
    7. 'require' // for Webpack/Browserify
    8. )
    9. const warnNonPresent = (target, key) => {
    10. warn(
    11. `Property or method "${key}" is not defined on the instance but ` +
    12. 'referenced during render. Make sure that this property is reactive, ' +
    13. 'either in the data option, or for class-based components, by ' +
    14. 'initializing the property. ' +
    15. 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
    16. target
    17. )
    18. }
    19. const warnReservedPrefix = (target, key) => {
    20. warn(
    21. `Property "${key}" must be accessed with "$data.${key}" because ` +
    22. 'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
    23. 'prevent conflicts with Vue internals. ' +
    24. 'See: https://vuejs.org/v2/api/#data',
    25. target
    26. )
    27. }
    28. const hasProxy =
    29. typeof Proxy !== 'undefined' && isNative(Proxy)
    30. if (hasProxy) {
    31. const isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact')
    32. config.keyCodes = new Proxy(config.keyCodes, {
    33. set (target, key, value) {
    34. if (isBuiltInModifier(key)) {
    35. warn(`Avoid overwriting built-in modifier in config.keyCodes: .${key}`)
    36. return false
    37. } else {
    38. target[key] = value
    39. return true
    40. }
    41. }
    42. })
    43. }
    44. const hasHandler = {
    45. has (target, key) {
    46. const has = key in target
    47. const isAllowed = allowedGlobals(key) ||
    48. (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data))
    49. if (!has && !isAllowed) {
    50. if (key in target.$data) warnReservedPrefix(target, key)
    51. else warnNonPresent(target, key)
    52. }
    53. return has || !isAllowed
    54. }
    55. }
    56. const getHandler = {
    57. get (target, key) {
    58. if (typeof key === 'string' && !(key in target)) {
    59. if (key in target.$data) warnReservedPrefix(target, key)
    60. else warnNonPresent(target, key)
    61. }
    62. return target[key]
    63. }
    64. }
    65. initProxy = function initProxy (vm) {
    66. if (hasProxy) {
    67. // determine which proxy handler to use
    68. const options = vm.$options
    69. // options.render._withStripped 一般只有在测试的时候为 true,这也就一意味着,通常而言都是范式 hasHandler
    70. const handlers = options.render && options.render._withStripped
    71. ? getHandler
    72. : hasHandler
    73. vm._renderProxy = new Proxy(vm, handlers)
    74. } else {
    75. vm._renderProxy = vm
    76. }
    77. }
    78. }