diff --git a/src/core/instance/proxy.js b/src/core/instance/proxy.js index 8c821baa09b..08d96513254 100644 --- a/src/core/instance/proxy.js +++ b/src/core/instance/proxy.js @@ -24,6 +24,16 @@ if (process.env.NODE_ENV !== 'production') { ) } + 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://vuejs.org/v2/api/#data', + target + ) + } + const hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy) @@ -45,9 +55,11 @@ if (process.env.NODE_ENV !== 'production') { const hasHandler = { has (target, key) { const has = key in target - const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_') + const isAllowed = allowedGlobals(key) || + (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)) if (!has && !isAllowed) { - warnNonPresent(target, key) + if (key in target.$data) warnReservedPrefix(target, key) + else warnNonPresent(target, key) } return has || !isAllowed } @@ -56,7 +68,8 @@ if (process.env.NODE_ENV !== 'production') { const getHandler = { get (target, key) { if (typeof key === 'string' && !(key in target)) { - warnNonPresent(target, key) + if (key in target.$data) warnReservedPrefix(target, key) + else warnNonPresent(target, key) } return target[key] } diff --git a/test/unit/features/instance/render-proxy.spec.js b/test/unit/features/instance/render-proxy.spec.js index 9a2365ae4c1..8da17172608 100644 --- a/test/unit/features/instance/render-proxy.spec.js +++ b/test/unit/features/instance/render-proxy.spec.js @@ -45,5 +45,49 @@ if (typeof Proxy !== 'undefined') { expect(vm.$el.textContent).toBe('foo') }) + + it('should warn properties starting with $ when found', () => { + new Vue({ + data: { $a: 'foo' }, + template: `