This article participated in the weekly reading activity of source code jointly initiated by the public account @Ruochuan Vision.Click to learn more about participating.
The source code
Source code address: github1s.com/vuejs/vue-n…
import { makeMap } from './makeMap' / / introduction
export { makeMap } // We can export it again.
// Introduce other file variables
export * from './patchFlags'
export * from './shapeFlags'
export * from './slotFlags'
export * from './globalsWhitelist'
export * from './codeframe'
export * from './normalizeProp'
export * from './domTagConfig'
export * from './domAttrConfig'
export * from './escapeHtml'
export * from './looseEqual'
export * from './toDisplayString'
export * from './typeUtils'
// The current development environment needs to report an error, need to determine dev
export const EMPTY_OBJ: { readonly [key: string] :any } = __DEV__
? Object.freeze({})
: {}
export const EMPTY_ARR = __DEV__ ? Object.freeze([]) : []
export const NOOP = () = > {} // Empty function 1. Easy to compress 2. Easy to judge
/** * Always return false. */
export const NO = () = > false // Also because of compression.
const onRE = /^on[^a-z]/ // Start with on followed by non-A-z letters
export const isOn = (key: string) = > onRE.test(key) // onClick
// Get the string beginning onUpdate
export const isModelListener = (key: string) = > key.startsWith('onUpdate:')
export const extend = Object.assign / / compression
export const remove = <T>(arr: T[], el: T) = > { // Delete the current index of the array
const i = arr.indexOf(el)
if (i > -1) {
arr.splice(i, 1)}}const hasOwnProperty = Object.prototype.hasOwnProperty / / compression
export const hasOwn = ( // Determine if it is its own key
val: object.key: string | symbol
): key is keyof typeof val => hasOwnProperty.call(val, key)
export const isArray = Array.isArray / / compression
export const objectToString = Object.prototype.toString / / compression
export const toTypeString = (value: unknown): string= >
objectToString.call(value) // Get the current worth type string
export const isMap = (val: unknown): val is Map<any.any> =>
toTypeString(val) === '[object Map]' // Check whether it is map
export const isSet = (val: unknown): val is Set<any> =>
toTypeString(val) === '[object Set]' // Check if it is set
// toTypeString(val) === '[object Date]' also works
export const isDate = (val: unknown): val is Date => val instanceof Date
export const isFunction = (val: unknown): val is Function= >typeof val === 'function'
export const isString = (val: unknown): val is string= >typeof val === 'string'
export const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'
export const isObject = (val: unknown): val is Record<any.any> => val ! = =null && typeof val === 'object'
export constisPromise = <T = any>(val: unknown): val is Promise<T> => { return isObject(val) && isFunction(val.then) && isFunction(val.catch) } export const toRawType = (value: unknown): String => {// extract "RawType" from strings like "[object RawType]" return toTypeString(value).slice(8, -1) } export const isPlainObject = (val: unknown): ToTypeString (val) === '[object object]' export const isIntegerKey = (key: unknown) => isString(key) && key ! == 'NaN' && key[0] ! == '-' && '// the 0th term is not negative '' + parseInt(key, 10) === key /** * Make a map and return a function for checking if a key * is in that map. * IMPORTANT: all calls of this function must be prefixed with * /*#__PURE__*/ * So that rollup can tree-shake them if necessary. */ export function makeMap( str: string, expectsLowerCase? Boolean): (key: string) => Boolean {const map: Record<string, Boolean > = object. create(null) // Create an Object const list: Array<string> = str.split(',') for (let I = 0; i < list.length; I ++) {map[list[I]] = true} If not, return unprocessed lowercase. Do you have val return expecterCase in the current map? val => !! map[val.toLowerCase()] : val => !! Export const isReservedProp = /*#__PURE__*/ makeMap(// The leading comma is intentional so empty string "" is also included ',key,ref,ref_for,ref_key,' + 'onVnodeBeforeMount,onVnodeMounted,' + 'onVnodeBeforeUpdate,onVnodeUpdated,' + 'onVnodeBeforeUnmount,onVnodeUnmounted' ) export const isBuiltInDirective = /*#__PURE__*/ makeMap( 'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo' ) const cacheStringFunction = <T extends (str: string) => string>(fn: T): T => { const cache: Record<string, string> = object. create(null) return (STR: string) => { const hit = cache[str] return hit || (cache[str] = fn(str)) }) as any } const camelizeRE = /-(\w)/g /** * @private */ export const camelize = cacheStringFunction((str: string): string => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')) }) const hyphenateRE = /\B([A-Z])/g /** * @private */ export const hyphenate = cacheStringFunction((str: string) => str.replace(hyphenateRE, '-$1').toLowerCase() ) /** * @private */ export const capitalize = cacheStringFunction( (str: string) => str.charAt(0).toUpperCase() + str.slice(1) ) /** * @private */ export const toHandlerKey = cacheStringFunction((str: string) => str ? `on${capitalize(str)}` : // compare whether a value has changed, accounting for NaN. // Export const hasChanged = (value: any, oldValue: any): boolean => ! Object.is(value, oldValue) // Used to execute functions in the array. Export const invokeArrayFns = (FNS: Function[], arg? : any) => { for (let i = 0; i < fns.length; I++) {FNS [I] (arg)}} / / an enumerable object attribute export const def = (obj: object, the key: string | symbol, value: any) => { Object.defineProperty(obj, key, { configurable: true, enumerable: // export const toNumber = (val: any): Any => {const n = parseFloat(val) return isNaN(n)? Val: n} any export const getGlobalThis = (): any => { return ( _globalThis || (_globalThis = typeof globalThis ! == 'undefined' // globalThis dynamically gets this of the current environment. ? globalThis : typeof self ! == 'undefined' // Web Worker can use self to access this, can't get window? self : typeof window ! == 'undefined' // browser? window : typeof global ! == 'undefined' // node ? Global: {}) // other: applet etc.)}Copy the code
conclusion
1. Import other file variables
export * from './patchFlags'
Copy the code
Divide content of the same type into a file within the project and import it as *. Then export it uniformly from index.js
2. Judge _DEV_
export const EMPTY_OBJ: { readonly [key: string] :any } = __DEV__
? Object.freeze({})
: {}
Copy the code
The dev environment is determined because the development environment requires an error message, but the production environment does not. So the production environment is a {} with no freeze
3. Empty function
// Usage scenarios: 1. Easy to judge 2. Easy to compress
export const NOOP = () = > {} / / empty function
// 1
const fn = NOOP
if (fn === NOOP) {// The function that is currently initialized has not changed yet.
// 2. Easy compression
function a() {
return () = > {} // The current function is anonymous and cannot be compressed
}
function a() {
return NOOP // You can compress variables
}
Copy the code
4. Delete array index entries
export const remove = <T>(arr: T[], el: T) = > { // Drop the current index O(n)
const i = arr.indexOf(el)
if (i > -1) {
arr.splice(i, 1)}}// In axios, instead of deleting the current item in the array, we just look up O(1) and assign it to null.
// Does not cause array displacement, affecting efficiency. However, I still need to see the specific use of the array, otherwise too much judgment, may not be worth the loss
/ / declare
this.handlers = [];
/ / remove
if (this.handlers[id]) {
this.handlers[id] = null;
}
/ / execution
if(h ! = =null) {
fn(h);
}
Copy the code
5. Cache the string processed by the function
constcacheStringFunction = <T extends (str: string) => string>(fn: T): T => { const cache: Record<string, string> = object. create(null) return (STR: string) => { const hit = cache[str] return hit || (cache[str] = fn(str)) }) as any } // \w -> 0-9a-zA-Z_ const camelizeRE = /-(\w)/g /** * @private */ export const camelize = cacheStringFunction((str: string): string => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : Const hyphenateRE = /\B([a-z])/g // \B([a-z])/ ** * @private */ export const hyphenate = cacheStringFunction((str: string) => str.replace(hyphenateRE, '-$1').TolowerCase ()) // ** * @private */ / acc => ACC Export Const Capitalize = cacheStringFunction( (str: string) => str.charAt(0).toUpperCase() + str.slice(1) ) /** * @private */ export const toHandlerKey = cacheStringFunction((str: string) => str ? 'on${capitalize(STR)}' : 'Copy the code
CacheStringFunction does string caching to prevent function processing every time.
constcacheStringFunction = <T extends (str: string) => string>(fn: T): T => { const cache: Record<string, string> = object. create(null) // Create cache Object // Cache is {'creat-time': 'creatTime'} return ((STR: String) = > {const hit = cache (STR) / / the second directly from the cache object already processed to return the content of the hit | | (cache (STR) = fn (STR))}) as any} const CamelizeRE = /-(\w)/g /** * @private */ const camelize = cacheStringFunction((STR) => {console.log(1)) Return str.replace(camelizeRE, (_, c) => (c? c.toUpperCase() : '')) }) console.log(camelize('creat-time')) console.log(camelize('creat-time'))Copy the code
6. Object.defineProperty
Overrides the descriptor of a property object
The data descriptor (enumerable, 64x, value, writable) and the access descriptor (Enumerable, 64X, set(), get()) are mutually exclusive. After defining set() and get(), the descriptor assumes that the access operation has already been defined, where defining value and writable raises an error.
let person = {}
Object.defineProperty(person, 'legs', {
value: 2.writable: true.configurable: true.enumerable: true
});
// Add legs to person with a value of 2
Copy the code
7. globalThis
Developer.mozilla.org/zh-CN/docs/…
Reference documentation
Juejin. Cn/post / 699497…