This article is not going to parse the operating principle of Vue source code, only to explore the tools in Vue functions that are worth learning SAO operation

The ultimate goal: to extend the knowledge from the utility functions

1. A series of judgments about the current environment

1.1inBrowser: checks whether the current host environment is a browser

// Check whether the 'window' object existsexport const inBrowser = typeof window ! = ='undefined'
Copy the code

1.2 hasProto: Checks whether the current environment can use the object__proto__attribute

// The __proto__ attribute of an object points to the prototype of its constructor // Starting with an empty object literal and progressing down the prototype chain.export const hasProto = '__proto__' in {}
Copy the code

2. user AgentA series of operations on a constant

2.1 Obtain the browseruser Agent

// toLowerCase is intended for subsequent environmental testingexport const UA = inBrowser && window.navigator.userAgent.toLowerCase()
Copy the code

2.2 Internet Explorer

export const isIE = UA && /msie|trident/.test(UA)

Parse: Use the re to match whether the UA contains'msie'or'trident'The two strings determine whether the browser is Internet Explorer

Source: Internet Explorer User Agent Strings

Multi-keyword highlighting plugin: multi-highlight

2.3 IE9| Edge | Chromejudge

export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
export const isEdge = UA && UA.indexOf('edge/') > 0
exportconst isChrome = UA && /chrome\/\d+/.test(UA) && ! isEdgeCopy the code

3. String operations

3.1 isReserved: Checks whether the string starts with $or _

// The charCodeAt() method returns the Unicode encoding of the character at the specified positionexport function isReserved (str: string): boolean {
  const c = (str + ' ').charCodeAt(0)
  return c === 0x24 || c === 0x5F
}
Copy the code

Parse: Get the Unicode of the first character of the string and compare it to 0x24 and 0x5F.

If you want to advance as an advanced front end, charCodeAt method of various uses still need to know (interview algorithm questions various tests).

3.1.2 JavascriptIntermediate algorithmcharCodeAt

Find the missing letter from the sequence of letters passed in and return it. For example, fearNotLetter(“abce”) should return “d”.

functionFearNotLetter (STR) {// Convert the string to ASCII and store it in an arraylet arr=[];
  for(let i=0; i<str.length; i++){
    arr.push(str.charCodeAt(i));
  }
  for(let j=1; j<arr.length; j++){
    letnum=arr[j]-arr[j-1]; // Check whether the last item minus the last item is 1. If it is not 1, the previous item of the character is missingif(num! =1){// convert missing ASCII characters to characters and returnreturnString.fromCharCode(arr[j]-1); }}return undefined;
}
fearNotLetter("abce") / /"d"
Copy the code

3.2 camelize: Hyphen to hump

const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : ' ')})Copy the code

Parse: Define a regular expression: /-(\w)/g to globally match a character following a hyphen and a hyphen in a string. If caught, replace the character with toUpperCase uppercase, otherwise with ”. Camelize (‘aa-bb’) // aaBb

3.3 toString: converts the value of a given variable to string and returns it

export function toString (val: any): string {
  return val == null
    ? ' '
    : typeof val === 'object'
      ? JSON.stringify(val, null, 2)
      : String(val)
}
Copy the code

Vue is filled with many of these enhanced packages, which greatly reduce the complexity of our code. But here, we’re going to learn how to use this multiple ternary operator

3.3.1 Multiple ternary operators

export function toString (val: any): string {
  return val == null
    ? ' '
    : typeof val === 'object'
      ? JSON.stringify(val, null, 2)
      : String(val)
}
Copy the code

Resolution:

export function toString (val: any): string {
  returnWhen the variable value is null? Return an empty string: otherwise, determine if the variable type is object? Returns json. stringify(val, null, 2) : otherwise String(val)}Copy the code

Similar operations are available in the vue source code. Such as mergeHook

3.3.2 rainfall distribution on 10-12mergeHook: Merges lifecycle options

functionmergeHook ( parentVal: ? Array<Function>, childVal: ? Function | ? Array<Function> ): ? Array<Function> {return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}
Copy the code

We don’t care what the mergeHook does in the source code (is there a lifecycle hook function that corresponds to the parent component and then concat it

3.4 capitalize: Capitalize the first character

/ / ignore cachedexport const capitalize = cached((str: string): string => {
  return str.charAt(0).toUpperCase() + str.slice(1)
})
Copy the code

Parsing: str.charat (0) takes the first item of STR, converts it toUpperCase using toUpperCase(), and str.slice(1) takes the STR part dividing the first item.

3.5 hyphenate: Turn the hump to hyphen

const hyphenateRE = /\B([A-Z])/g
export const hyphenate = cached((str: string): string => {
  return str.replace(hyphenateRE, '- $1').toLowerCase()
})
Copy the code

A. camelize B. camelize Again, use the re, /\B([a-z])/g to globally match the uppercase characters in the string and then replace them.

4. Type judgment

4.1 isPrimitive: Determines whether the variable is of prototype type

export function isPrimitive (value: any): boolean %checks {
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    // $flow-disable-line
    typeof value === 'symbol' ||
    typeof value === 'boolean')}Copy the code

2. The symbol type is often ignored.

4.2 isRegExp: Determines whether the variable is a regular object.

/ / use the Object. The prototype. ToString and'[object RegExp]'Do congruent comparison.export function isRegExp (v: any): boolean {
  return _toString.call(v) === '[object RegExp]'
}
Copy the code

This is also the most accurate way to determine the type, and the same is true for other types in Vue

4.3 isValidArrayIndex: Determines whether the variable contains a valid array index

export functionisValidArrayIndex (val: any): Boolean {const n = parseFloat(String(val)) // n >= 0 && math.floor (n) === n Guarantee that the index is an integer greater than or equal to 0return n >= 0 && Math.floor(n) === n && isFinite(val)
}
Copy the code

The isFinite method checks the value of its arguments. Returns false if the argument is NaN, plus infinity or minus infinity, and true otherwise.

Extension: Syntax: isFinite()

4.4 isObject: Distinguishes objects from raw values

export function isObject (obj: mixed): boolean %checks {
  returnobj ! == null && typeof obj ==='object'
}
Copy the code

5. Closure SAO in Vue

5.1 makeMap(): Determines whether a variable is included in the passed string

export functionmakeMap ( str: string, expectsLowerCase? : boolean ): (key: string) =>true | void {
  const map = Object.create(null)
  const list: Array<string> = str.split(', ')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
}
Copy the code
  1. Defining an objectmap
  2. willstrPartition into an array and save tolistvariable
  3. traverselistAnd in order tolistAs an element inmapkey, and set it totrue
  4. Returns a function and ifexpectsLowerCasefortrueIf so, lower casemap[key]:

Let’s use an example to illustrate:

let isMyName = makeMap("Front end dispeller, handsome bee.".true); // set a method that detects if it isMyName. The second parameter is case insensitive.'Front end troubleshooter') / /true
isMyName('handsome than') / /true
isMyName('ugly force') / /false
Copy the code

There are many similar judgments in Vue, and they are very practical.

5.1.1 isHTMLTag | isSVG | isReservedAttr

These three functions are generated by makeMap to check whether an attribute (tag) is a reserved attribute (tag)

export const isHTMLTag = makeMap(
  'html,body,base,head,link,meta,style,title,' +
  'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
  'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
  'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
  's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
  'embed,object,param,source,canvas,script,noscript,del,ins,' +
  'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
  'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
  'output,progress,select,textarea,' +
  'details,dialog,menu,menuitem,summary,' +
  'content,element,shadow,template,blockquote,iframe,tfoot'
)
export const isSVG = makeMap(
  'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
  'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
  'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view'.true// The reserved attributes for the Web platform are style and classexport const isReservedAttr = makeMap('style,class')
Copy the code

5.2 once: a function that is called only once

export function once (fn: Function): Function {
  let called = false
  return function () {
    if(! called) { called =true
      fn.apply(this, arguments)
    }
  }
}
Copy the code

解析 : the callback identifier is called. When this function is called, the called identifier changes and the next call is invalid. Is also a typical closure call.

5.3 cache: Creates a cache function

/**
 * Create a cached version of a pure function.
 */
export function cached<F: Function> (fn: F): F {
  const cache = Object.create(null)
  return (function cachedFn (str: string) {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }: any)
}
Copy the code

The comment here explains why.

Const cache = object.create (null) Const cache = object.create (null) Const cache = object.create (null) Const cache = object.create (null)

In Vue, many of the same strings need to be translated, and re-translating each time can cause a lot of unnecessary overhead. The cache function reads from the cache. If it is not in the cache, it is stored in the cache and then read again.

6. Multiple types of congruent judgment

looseEqual: Checks whether two values are equal

export functionLooseEqual (a: any, b: any): Boolean {// Return when a === btrue
  if (a === b) return trueConst isObjectA = isObject(a) const isObjectB = isObject(b) const isObjectA = isObject(a) const isObjectB = isObject(bif(isObjectA && isObjectB) {try {// Call the array.isarray () method, (typeof) const isArrayA = array.isArray (a) const isArrayB = array.isArray (b))if(isArrayA && isArrayB) {// compare the lengths of arrays a and bsreturnA.query === b.query && a.query ((e, I) => {// call looseEqual to enter recursionreturn looseEqual(e, b[i])
        })
      } else if(! isArrayA && ! Const keysA = object.keys (a) const keysB = object.keys (b) const keysB = object.keys (breturnKeysa. length === keysb.length && keysa. every(key => {// the length is equal, then call looseEqual to enter recursionreturn looseEqual(a[key], b[key])
        })
      } else{// if a is an array and b is an object, returnfalse
        /* istanbul ignore next */
        return false
      }
    } catch (e) {
      /* istanbul ignore next */
      return false}}else if(! isObjectA && ! isObjectB) {return String(a) === String(b)
  } else {
    return false}}Copy the code

This function is longer and is recommended to be used with comments. Anyway, it’s

Various types of judgment + recursion

A collection of the author’s articles

  • “Learn from source code” thoroughly understand the Vue option Props
  • “Vue Practice” project to upgrade vue-CLI3 correct posture
  • “Learn from the source code” Vue source code in JS SAO operation
  • Why do you never understand JavaScript scope chains?