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…