debug.js

Is the so-called whetstone is not wrong to cut wood workers, before really reading the source code to understand some variables is how to judge, the role of pure function is very necessary. Know what hammers, axes, wrenches, and scissors are for so you don’t feel unprepared when you meet them for the first time.

This file mainly exposes four methods warn, TIP, generateComponentTrace, formatComponentName, the main code is as follows

//noop is an empty method introduced from shared/util
export function noop (a? : any, b? : any, c? : any) {}

//debug.js
export let warn = noop
export let tip = noop
export let generateComponentTrace = (noop: any) // work around flow check
export let formatComponentName = (noop: any)
if(process.env.NODE_ENV ! = ='production') {
	// Ignore this part for now
}
Copy the code

They are mainly used in debugging, but in production they are just empty functions and do nothing, and only in development will they be redefined.

Process.env.node_env! == ‘production’, this is from the performance perspective, some tests, warnings and other unnecessary prompts will only be processed in non-production environment to achieve optimal performance.

// Check whether the current environment supports console
const hasConsole = typeof console! = ='undefined'
// Regular expressions
const classifyRE = / (? :^|[-_])(\w)/g
// Convert the string format
const classify = str= > str
    .replace(classifyRE, c= > c.toUpperCase())
    .replace(/[-_]/g.' ')
Copy the code

The previous two are relatively easy to understand. The purpose of false is to convert the horizontal script in the string to camel form using the regular classifyRE. Such as:

classify('fishing-wang');
/ / output FisingWang
Copy the code
// Overwrite the print or warning content to the client
warn = (msg, vm) = > {
  const trace = vm ? generateComponentTrace(vm) : ' '
  if (config.warnHandler) {
    config.warnHandler.call(null, msg, vm, trace)
  } else if(hasConsole && (! config.silent)) {console.error(`[Vue warn]: ${msg}${trace}`)
  }
}

tip = (msg, vm) = > {
  if(hasConsole && (! config.silent)) {console.warn(`[Vue tip]: ${msg}` + (
      vm ? generateComponentTrace(vm) : ' '))}}Copy the code

env.js

Is the so-called whetstone is not wrong to cut wood workers, before really reading the source code to understand some variables is how to judge, the role of pure function is very necessary. Know what hammers, axes, wrenches, and scissors are for so you don’t feel unprepared when you meet them for the first time.

Checks the current host environment’s support for variables.

// Check whether the current browser supports '__proto__'
export const hasProto = '__proto__' in {}
// Check whether the browser environment exists
export const inBrowser = typeof window! = ='undefined'
// Check whether the current environment is weeX
export const inWeex = typeofWXEnvironment ! = ='undefined'&&!!!!! WXEnvironment.platform// Whether weeX platform
export const weexPlatform = inWeex && WXEnvironment.platform.toLowerCase()
// Make sure that the current environment is a browser environment, then save the browser's use Agent information in the UA variable (for non-browser environment, return false)
export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
// Whether to use Internet Explorer
export const isIE = UA && /msie|trident/.test(UA)
// Whether Internet Explorer 9 is used
export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
// Whether to use Edge browser
export const isEdge = UA && UA.indexOf('edge/') > 0
// Whether to use Android
export const isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android')
// Whether to use the IOS environment
export const isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios')
// Whether Chrome environment is available
export const isChrome = UA && /chrome\/\d+/.test(UA) && ! isEdge/ / the window. The navigator. Whether the userAgent contains phantomjs keyword
export const isPhantomJS = UA && /phantomjs/.test(UA)
// Whether the Firefox browser environment is available
export const isFF = UA && UA.match(/firefox\/(\d+)/)
Copy the code
export const nativeWatch = ({}).watch
Copy the code

The Object.prototype.watch method is provided natively in Firefox. So nativeWatch returns the correct function only if the current host environment is Firefox, otherwise it returns undefined. It can also be used to distinguish watches in VUE instances to prevent conflicts from causing accidents.

// Test whether the current browser supports passive through the listener call test-passive.
// The code is wrapped with a try catch, indicating poor support and error prone
export let supportsPassive = false
if (inBrowser) {
  try {
    const opts = {}
    Object.defineProperty(opts, 'passive', ({
      get () {
        supportsPassive = true
      }
    }: Object))
    window.addEventListener('test-passive'.null, opts)
  } catch (e) {}
}

// Check whether the server environment exists
let _isServer
export const isServerRendering = () = > {
  if (_isServer === undefined) {
    if(! inBrowser && ! inWeex &&typeof global! = ='undefined') {
      _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'
    } else {
      _isServer = false}}return _isServer
}

// Check whether the tool environment is developed
export const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__
Copy the code
// Check whether the current method is provided by native JS
export function isNative (Ctor: any) :boolean {
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

// Checks whether the current host environment supports native symbol reflects. ownKeys, which returns a Boolean value
export const hasSymbol =
  typeof Symbol! = ='undefined' && isNative(Symbol) &&
  typeof Reflect! = ='undefined' && isNative(Reflect.ownKeys)
Copy the code

lang.js

Is the so-called whetstone is not wrong to cut wood workers, before really reading the source code to understand some variables is how to judge, the role of pure function is very necessary. Know what hammers, axes, wrenches, and scissors are for so you don’t feel unprepared when you meet them for the first time.

This file exposes only one variable and three methods

export const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3 001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/
Copy the code

Unicode regular expression used to parse the template template

export function isReserved (str: string) :boolean {
  const c = (str + ' ').charCodeAt(0)
  return c === 0x24 || c === 0x5F
}
Copy the code

Checking whether a string begins with an _ or dollar sign $is used to check whether variables in VUE component instances are properly named (VUE does not recommend naming variables in strings starting with _ or $, which is the framework’s way of naming names).

export function def (obj: Object, key: string, val: any, enumerable? : boolean) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable:!!!!! enumerable,writable: true.configurable: true})}Copy the code

Object.defineproperty is wrapped in a simple wrapper, presumably to make it easier to call. The def function takes four arguments: the source object itself, the key value, the value, the enumerable or not. The final argument enumerable is optional.

const bailRE = new RegExp(` [^${unicodeRegExp.source}.$_\\d]`)
export function parsePath (path: string) :any {
  if (bailRE.test(path)) {
    return
  }
  const segments = path.split('. ')
  return function (obj) {
    for (let i = 0; i < segments.length; i++) {
      if(! obj)return
      obj = obj[segments[i]]
    }
    return obj
  }
}
Copy the code

For a simple parse of a path, this method is relatively simple: return if path is regular (e.g., ~, /, *), otherwise Cut the path into an array, store it in segments, and return a function that iterates through the segments to get an object. This method is mainly used to trigger the reading of values when initializing the Watcher.

perf.js

Is the so-called whetstone is not wrong to cut wood workers, before really reading the source code to understand some variables is how to judge, the role of pure function is very necessary. Know what hammers, axes, wrenches, and scissors are for so you don’t feel unprepared when you meet them for the first time.

Performance Monitoring

Define two variables mark and measure that are used to monitor performance in non-production environments. In production environments, no monitoring is required and undefined is returned. Source code is as follows:

import { inBrowser } from './env'

export let mark
export let measure

if(process.env.NODE_ENV ! = ='production') {
  const perf = inBrowser && window.performance
  /* istanbul ignore if */
  if (
    perf &&
    perf.mark &&
    perf.measure &&
    perf.clearMarks &&
    perf.clearMeasures
  ) {
    mark = tag= > perf.mark(tag)
    measure = (name, startTag, endTag) = > {
      perf.measure(name, startTag, endTag)
      perf.clearMarks(startTag)
      perf.clearMarks(endTag)
      // perf.clearMeasures(name)}}}Copy the code

Perf is window.performance if and only if the host is a browser and in a non-production environment. Multiple judgments are made in the if statement to ensure that the current environment supports window.performance. After that, mark and measure were redefined. The result of the simplification of the above code in non-production environment is as follows:

const mark = tag= > window.performance.mark(tag);
const measure = (name,startTag,endTag) = > {
	window.performance.measure(name,startTag,endTag)
	window.performance.clearMarks(startTag)
	window.performance.clearMarks(endTag)
}
Copy the code

What is window.performance?

The Web Performance API allows Web pages to access certain functions to measure the Performance of Web pages and Web applications. For details, go to window.Performance

shared/util.js

Is the so-called whetstone is not wrong to cut wood workers, before really reading the source code to understand some variables is how to judge, the role of pure function is very necessary. Know what hammers, axes, wrenches, and scissors are for so you don’t feel unprepared when you meet them for the first time.

emptyObject

export const emptyObject = Object.freeze({})
Copy the code

Create a frozen emptyObject, which means that the emptyObject is not extensible, that is, no new attributes can be added

isUndef

export function isUndef (v: any) :boolean %checks {
  return v === undefined || v === null
}
Copy the code

To determine whether a variable is undefined, that is, if it is defined as unassigned, or if it is assigned to null

isDef

export function isDef (v: any) :boolean %checks {
  returnv ! = =undefined&& v ! = =null
}
Copy the code

Determines whether a variable is defined

isTrue

export function isTrue (v: any) :boolean %checks {
  return v === true
}
Copy the code

Determines whether the variable is true

isFalse

export function isFalse (v: any) :boolean %checks {
  return v === false
}
Copy the code

Determine if the variable is false

isPrimitive

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

To determine whether a variable is a raw value, that is, to determine whether the variable is not compound data

isObject

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

Check whether a variable is an object or an array

toRawType

const _toString = Object.prototype.toString
export function toRawType (value: any) :string {
  return _toString.call(value).slice(8, -1)}Copy the code

Returns the original string type after determining the type. Such as judgment: an Array Object. The prototype. ToString. Call ([]) is the result of [the Object Array], then use the slice (8, 1) after the result is a string Array

isPlainObject

export function isPlainObject (obj: any) :boolean {
  return _toString.call(obj) === '[object Object]'
}
Copy the code

Determines whether a variable is a pure object

isRegExp

export function isRegExp (v: any) :boolean {
  return _toString.call(v) === '[object RegExp]'
}
Copy the code

Determines whether a variable is a regular object

isValidArrayIndex

export function isValidArrayIndex (val: any) :boolean {
  const n = parseFloat(String(val))
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}
Copy the code

Determines whether a variable is a valid array index.

  • A normal array index should be an integer greater than or equal to 0
  • The variable is parsed and returns a floating point number, stored in variable n
  • Returns true if and only if the variable is greater than or equal to 0, is an integer, and is a finite number

isPromise

export function isPromise (val: any) :boolean {
  return (
    isDef(val) &&
    typeof val.then === 'function' &&
    typeof val.catch === 'function')}Copy the code

Determine if a variable is a Promise

toString

export function toString (val: any) :string {
  return val == null
    ? ' '
    : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
      ? JSON.stringify(val, null.2)
      : String(val)
}
Copy the code

Convert variables to string format

  • If null, an empty string is returned
  • If it is an array or a pure object, use json.stringify
  • Other cases are handled directly by the String function

toNumber

export function toNumber (val: string) :number | string {
  const n = parseFloat(val)
  return isNaN(n) ? val : n
}
Copy the code

Converts a variable to a numeric type, returning the initial value if the conversion fails (for example, converting the string “aaa” yields NaN)

makeMap

export function makeMap (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

Returns a function that determines whether a given string contains the specified content (mapping).

STR data format :a string of long intervals, such as a, B, C, D, and E expectercase: Specifies whether to lowercase the map value key

Use examples (check for lowercase vowels) :

let isLower = makeMap('a,b,c,d,e');
isLower('b');  // true
isLower('f');  // undefined
Copy the code

remove

export function remove (arr: Array<any>, item: any) :Array<any> | void {
  if (arr.length) {
    const index = arr.indexOf(item)
    if (index > -1) {
      return arr.splice(index, 1)}}}Copy the code

Removes the given element from an array and returns an array of the deleted items: [item]

If the array is not empty, get the number of the current element. If the element exists (greater than -1), splice will be used to delete it and return a new array of the deleted elements. Otherwise, undefined will be returned

Example:

let arr = ['a'.'b'.'c'];
remove(arr,'a');  // ['a']
/ / arr into [' b ', 'c']
Copy the code

hasOwn

/ / encapsulation ` Object. The prototype. HasOwnProperty `, used to detect whether a given Object containing a given ` key ` values
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj: Object | Array<*>, key: string) :boolean {
  return hasOwnProperty.call(obj, key)
}
Copy the code

cached

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

Creates a cached version of a function for a pure function creation. The input argument must be a pure function and the return must be a pure function.

  • The first step is to determine why we must pass a pure function, because the output of a pure function depends only on the input, and the environment in which it is run cannot change the output.
  • Create a closure object with an empty prototype chaincacheUsed to cache results.
  • A function is then returnedcachedFn, read the cache first, if there is, return the returned value, otherwise use the original functionfnCompute once and cache the results.

camelize

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

Converts the hyphen to camel name

capitalize

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

Change the first letter of the string to uppercase

hyphenate

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

As opposed to the camelize method, change the camel name to a hyphen. For example: hyphenateRE(‘aaBb’) => AA-bb

polyfillBind

nativeBind

bind

function polyfillBind (fn: Function, ctx: Object) :Function {
  function boundFn (a) {
    const l = arguments.length
    return l
      ? l > 1
        ? fn.apply(ctx, arguments)
        : fn.call(ctx, a)
      : fn.call(ctx)
  }

  boundFn._length = fn.length
  return boundFn
}

function nativeBind (fn: Function, ctx: Object) :Function {
  return fn.bind(ctx)
}

export const bind = Function.prototype.bind
  ? nativeBind
  : polyfillBind
Copy the code

This is essentially a bind function that returns a new function that this points to.

  • polyfillBindA binding function that is written manually
  • nativeBindNative binding functions on the Function prototype chain
  • bindWhether native binding functions are supported or not is preferred; otherwise, manually implemented functions are used

toArray

export function toArray (list: any, start? : number) :Array<any> {
  start = start || 0
  let i = list.length - start
  const ret: Array<any> = new Array(i)
  while (i--) {
    ret[i] = list[i + start]
  }
  return ret
}
Copy the code

A method that converts an array of classes to an array starting at the specified position (0 by default).

  • listAn array of class
  • startOptional starting index location

extend

export function extend (to: Object, _from: ?Object) :Object {
  for (const key in _from) {
    to[key] = _from[key]
  }
  return to
}
Copy the code

Copies data from one object (_from) to another object (to). If the key value is duplicate, the data in _from will be replaced by the data in to. Note: If value is compound data, it is a shallow copy.

toObject

export function toObject (arr: Array<any>) :Object {
  const res = {}
  for (let i = 0; i < arr.length; i++) {
    if (arr[i]) {
      extend(res, arr[i])
    }
  }
  return res
}
Copy the code

Iterates through each object element of the array, copies the contents to a new object, and returns the new object. The for loop iterates through the array, is used with extend, and is copied into the new object res. The logic is simple.

noop

export function noop (a? : any, b? : any, c? : any) {}
Copy the code

An empty function that does nothing.

no

export const no = (a? : any, b? : any, c? : any) = > false
Copy the code

Function that always returns false.

identity

export const identity = (_: any) = > _
Copy the code

A pure function that returns the input value directly

genStaticKeys

export function genStaticKeys (modules: Array<ModuleOptions>) :string {
  return modules.reduce((keys, m) = > {
    return keys.concat(m.staticKeys || [])
  }, []).join(', ')}Copy the code

Generates a string containing static keys from the compiler module.

  • modulesIs an array, an option of the compiler, where each element is a possible containstaticKeysProperty. The purpose of this method is to iterate through a set of elements and collectstaticKeysIn order to.Separate the concatenation string composed of.

looseEqual

export function looseEqual (a: any, b: any) :boolean {
  if (a === b) return true
  const isObjectA = isObject(a)
  const isObjectB = isObject(b)
  if (isObjectA && isObjectB) {
    try {
      const isArrayA = Array.isArray(a)
      const isArrayB = Array.isArray(b)
      if (isArrayA && isArrayB) {
        return a.length === b.length && a.every((e, i) = > {
          return looseEqual(e, b[i])
        })
      } else if (a instanceof Date && b instanceof Date) {
        return a.getTime() === b.getTime()
      } else if(! isArrayA && ! isArrayB) {const keysA = Object.keys(a)
        const keysB = Object.keys(b)
        return keysA.length === keysB.length && keysA.every(key= > {
          return looseEqual(a[key], b[key])
        })
      } else {
        /* 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

Determine whether two values are congruent.

looseIndexOf

export function looseIndexOf (arr: Array<mixed>, val: mixed) :number {
  for (let i = 0; i < arr.length; i++) {
    if (looseEqual(arr[i], val)) return i
  }
  return -1
}
Copy the code

Finds if the given element is in the specified array, returns the index of the current element’s array if it is, or -1 otherwise.

once

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

Implement a function that is called only once using the features of closures.