diff --git a/packages/runtime-dom/src/directives/vOn.ts b/packages/runtime-dom/src/directives/vOn.ts index c1a2e182f00..44b7958846d 100644 --- a/packages/runtime-dom/src/directives/vOn.ts +++ b/packages/runtime-dom/src/directives/vOn.ts @@ -52,21 +52,24 @@ const modifierGuards: Record< export const withModifiers = < T extends (event: Event, ...args: unknown[]) => any, >( - fn: T & { _withMods?: { [key: string]: T } }, + fn: T & { _withMods?: Map }, modifiers: VOnModifiers[], ): T => { - const cache = fn._withMods || (fn._withMods = {}) + const cache = fn._withMods || (fn._withMods = new Map()) const cacheKey = modifiers.join('.') - return ( - cache[cacheKey] || - (cache[cacheKey] = ((event, ...args) => { - for (let i = 0; i < modifiers.length; i++) { - const guard = modifierGuards[modifiers[i] as ModifierGuards] - if (guard && guard(event, modifiers)) return - } - return fn(event, ...args) - }) as T) - ) + const cached = cache.get(cacheKey) + if (cached) { + return cached + } + const modifier = ((event, ...args) => { + for (let i = 0; i < modifiers.length; i++) { + const guard = modifierGuards[modifiers[i] as ModifierGuards] + if (guard && guard(event, modifiers)) return + } + return fn(event, ...args) + }) as T + cache.set(cacheKey, modifier) + return modifier } // Kept for 2.x compat. @@ -88,7 +91,7 @@ const keyNames: Record< * @private */ export const withKeys = any>( - fn: T & { _withKeys?: { [k: string]: T } }, + fn: T & { _withKeys?: Map }, modifiers: string[], ): T => { let globalKeyCodes: LegacyConfig['keyCodes'] @@ -110,54 +113,60 @@ export const withKeys = any>( } } - const cache: { [k: string]: T } = fn._withKeys || (fn._withKeys = {}) + const cache: Map = fn._withKeys || (fn._withKeys = new Map()) const cacheKey = modifiers.join('.') - return ( - cache[cacheKey] || - (cache[cacheKey] = (event => { - if (!('key' in event)) { - return - } + const cached = cache.get(cacheKey) + if (cached) { + return cached + } - const eventKey = hyphenate(event.key) + const withKey = (event => { + if (!('key' in event)) { + return + } + + const eventKey = hyphenate(event.key) + if ( + modifiers.some( + k => + k === eventKey || + keyNames[k as unknown as CompatModifiers] === eventKey, + ) + ) { + return fn(event) + } + + if (__COMPAT__) { + const keyCode = String(event.keyCode) if ( - modifiers.some( - k => - k === eventKey || - keyNames[k as unknown as CompatModifiers] === eventKey, - ) + compatUtils.isCompatEnabled( + DeprecationTypes.V_ON_KEYCODE_MODIFIER, + instance, + ) && + modifiers.some(mod => mod == keyCode) ) { return fn(event) } - - if (__COMPAT__) { - const keyCode = String(event.keyCode) - if ( - compatUtils.isCompatEnabled( - DeprecationTypes.V_ON_KEYCODE_MODIFIER, - instance, - ) && - modifiers.some(mod => mod == keyCode) - ) { - return fn(event) - } - if (globalKeyCodes) { - for (const mod of modifiers) { - const codes = globalKeyCodes[mod] - if (codes) { - const matches = isArray(codes) - ? codes.some(code => String(code) === keyCode) - : String(codes) === keyCode - if (matches) { - return fn(event) - } + if (globalKeyCodes) { + for (const mod of modifiers) { + const codes = globalKeyCodes[mod] + if (codes) { + const matches = isArray(codes) + ? codes.some(code => String(code) === keyCode) + : String(codes) === keyCode + if (matches) { + return fn(event) } } } } - }) as T) - ) + } + }) as T + + cache.set(cacheKey, withKey) + + return withKey } export type VOnDirective = Directive diff --git a/packages/runtime-dom/src/modules/style.ts b/packages/runtime-dom/src/modules/style.ts index 383628a6ad0..380cb766905 100644 --- a/packages/runtime-dom/src/modules/style.ts +++ b/packages/runtime-dom/src/modules/style.ts @@ -103,22 +103,24 @@ function setStyle( } const prefixes = ['Webkit', 'Moz', 'ms'] -const prefixCache: Record = {} +const prefixCache: Map = new Map() function autoPrefix(style: CSSStyleDeclaration, rawName: string): string { - const cached = prefixCache[rawName] + const cached = prefixCache.get(rawName) if (cached) { return cached } let name = camelize(rawName) if (name !== 'filter' && name in style) { - return (prefixCache[rawName] = name) + prefixCache.set(rawName, name) + return name } name = capitalize(name) for (let i = 0; i < prefixes.length; i++) { const prefixed = prefixes[i] + name if (prefixed in style) { - return (prefixCache[rawName] = prefixed) + prefixCache.set(rawName, prefixed) + return prefixed } } return rawName diff --git a/packages/server-renderer/src/helpers/ssrCompile.ts b/packages/server-renderer/src/helpers/ssrCompile.ts index 8412a65e843..b8223bfd532 100644 --- a/packages/server-renderer/src/helpers/ssrCompile.ts +++ b/packages/server-renderer/src/helpers/ssrCompile.ts @@ -17,7 +17,7 @@ type SSRRenderFunction = ( parentInstance: ComponentInternalInstance, ) => void -const compileCache: Record = Object.create(null) +const compileCache: Map = new Map() export function ssrCompile( template: string, @@ -62,7 +62,7 @@ export function ssrCompile( }, ) - const cached = compileCache[cacheKey] + const cached = compileCache.get(cacheKey) if (cached) { return cached } @@ -89,5 +89,8 @@ export function ssrCompile( 'vue/server-renderer': helpers, } const fakeRequire = (id: 'vue' | 'vue/server-renderer') => requireMap[id] - return (compileCache[cacheKey] = Function('require', code)(fakeRequire)) + + const ssrRenderFunction = Function('require', code)(fakeRequire) + compileCache.set(cacheKey, ssrRenderFunction) + return ssrRenderFunction } diff --git a/packages/shared/src/domAttrConfig.ts b/packages/shared/src/domAttrConfig.ts index b5f0166327f..249198ae3a0 100644 --- a/packages/shared/src/domAttrConfig.ts +++ b/packages/shared/src/domAttrConfig.ts @@ -34,17 +34,21 @@ export function includeBooleanAttr(value: unknown): boolean { } const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/ -const attrValidationCache: Record = {} +const attrValidationCache: Map = new Map() export function isSSRSafeAttrName(name: string): boolean { - if (attrValidationCache.hasOwnProperty(name)) { - return attrValidationCache[name] + const cached = attrValidationCache.get(name) + if (cached) { + return cached } + const isUnsafe = unsafeAttrCharRE.test(name) if (isUnsafe) { console.error(`unsafe attribute name: ${name}`) } - return (attrValidationCache[name] = !isUnsafe) + attrValidationCache.set(name, !isUnsafe) + + return !isUnsafe } export const propsToAttrMap: Record = { diff --git a/packages/shared/src/general.ts b/packages/shared/src/general.ts index 9c6a2313240..c58677c878e 100644 --- a/packages/shared/src/general.ts +++ b/packages/shared/src/general.ts @@ -38,14 +38,15 @@ export const hasOwn = ( export const isArray: typeof Array.isArray = Array.isArray export const isMap = (val: unknown): val is Map => - toTypeString(val) === '[object Map]' + !!val && (val as any)[Symbol.toStringTag] === 'Map' export const isSet = (val: unknown): val is Set => - toTypeString(val) === '[object Set]' + !!val && (val as any)[Symbol.toStringTag] === 'Set' export const isDate = (val: unknown): val is Date => toTypeString(val) === '[object Date]' export const isRegExp = (val: unknown): val is RegExp => - toTypeString(val) === '[object RegExp]' + // refer https://262.ecma-international.org/15.0/index.html#sec-isregexp + !!val && !!(val as any)[Symbol.match] export const isFunction = (val: unknown): val is Function => typeof val === 'function' export const isString = (val: unknown): val is string => typeof val === 'string' @@ -54,11 +55,7 @@ export const isObject = (val: unknown): val is Record => val !== null && typeof val === 'object' export const isPromise = (val: unknown): val is Promise => { - return ( - (isObject(val) || isFunction(val)) && - isFunction((val as any).then) && - isFunction((val as any).catch) - ) + return !!val && (val as any)[Symbol.toStringTag] === 'Promise' } export const objectToString: typeof Object.prototype.toString = @@ -94,10 +91,15 @@ export const isBuiltInDirective: (key: string) => boolean = ) const cacheStringFunction = string>(fn: T): T => { - const cache: Record = Object.create(null) + const cache: Map = new Map() return ((str: string) => { - const hit = cache[str] - return hit || (cache[str] = fn(str)) + const cached = cache.get(str) + if (cached) { + return cached + } + const res = fn(str) + cache.set(str, res) + return res }) as T } diff --git a/packages/shared/src/makeMap.ts b/packages/shared/src/makeMap.ts index e85efe21e5b..b1003b3b90f 100644 --- a/packages/shared/src/makeMap.ts +++ b/packages/shared/src/makeMap.ts @@ -8,7 +8,6 @@ /*! #__NO_SIDE_EFFECTS__ */ export function makeMap(str: string): (key: string) => boolean { - const map = Object.create(null) - for (const key of str.split(',')) map[key] = 1 - return val => val in map + const map = new Set(str.split(',')) + return val => map.has(val) } diff --git a/packages/vue-compat/src/index.ts b/packages/vue-compat/src/index.ts index d7e9695d824..879b0796ab6 100644 --- a/packages/vue-compat/src/index.ts +++ b/packages/vue-compat/src/index.ts @@ -26,7 +26,7 @@ import { warnDeprecation, } from '../../runtime-core/src/compat/compatConfig' -const compileCache: Record = Object.create(null) +const compileCache: Map = new Map() function compileToFunction( template: string | HTMLElement, @@ -42,7 +42,7 @@ function compileToFunction( } const key = genCacheKey(template, options) - const cached = compileCache[key] + const cached = compileCache.get(key) if (cached) { return cached } @@ -101,7 +101,8 @@ function compileToFunction( // mark the function as runtime compiled ;(render as InternalRenderFunction)._rc = true - return (compileCache[key] = render) + compileCache.set(key, render) + return render } registerRuntimeCompiler(compileToFunction) diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 785f3fd4bb4..79cc0788b9e 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -25,7 +25,7 @@ if (__DEV__) { initDev() } -const compileCache: Record = Object.create(null) +const compileCache: Map = new Map() function compileToFunction( template: string | HTMLElement, @@ -41,7 +41,7 @@ function compileToFunction( } const key = genCacheKey(template, options) - const cached = compileCache[key] + const cached = compileCache.get(key) if (cached) { return cached } @@ -98,7 +98,8 @@ function compileToFunction( // mark the function as runtime compiled ;(render as InternalRenderFunction)._rc = true - return (compileCache[key] = render) + compileCache.set(key, render) + return render } registerRuntimeCompiler(compileToFunction)