The entrance

const add = createMathOperation((augend, addend) = > augend + addend, 0)
Copy the code

createMathOperation

function createMathOperation(operator, defaultValue) {
  return (value, other) = > {
    // Exclude any value that is passed
    if (value === undefined && other === undefined) {
      return defaultValue
    }
    if(value ! = =undefined && other === undefined) {
      return value
    }
    if(other ! = =undefined && value === undefined) {
      return other
    }
    // There is a string type, which is converted to a string and added
    if (typeof value === 'string' || typeof other === 'string') {
      value = baseToString(value)
      other = baseToString(other)
    }
    // The default conversion is number type addition
    else {
      value = baseToNumber(value)
      other = baseToNumber(other)
    }
    / / return
    // The operator is (augend, addEnd) => Augend + addend
    return operator(value, other)
  }
}
Copy the code

Procedure: Determine the number of arguments -> Determine the type of arguments -> operation

Determine the number of arguments

The processing of undefined is used to deal with the situation that parameters are not transmitted or not transmitted

Determine the type of argument

Type to handle, string Boolean number symbol Object. The default behavior of string is to convert another value to string. For example, we usually use “+ 1” to convert other types of variables to strings. So strings require special handling

For Boolean, operations can be converted to 0 or 1 by default. If one of the values is string, it will be converted to ‘true’ and ‘false’

For symbol, have special treatment in the two methods, the string is returned to the empty string or call symbol. Prototype. ToString, number returns NaN

For the object

  • arrayAdding the numbers will callArray.prototype.toStringBy means ofbaseToNumberAfter conversion, returnNaN
  • dateAfter the baseToNumber conversion, the timestamp is returned. throughbaseToStringAfter conversion, returns a string in local time format, such asFri Jun 18 2021 18:42:53 GMT+0800 (China Standard Time)
  • regexpthroughbaseToNumberAfter conversion, returnNaN. throughbaseToStringAfter conversion, the corresponding regular expression is returned
  • nullthroughbaseToNumberAfter conversion, return0. throughbaseToStringReturns a string after conversion'null'

In summary, we just need to determine the number or string type to perform the operation

baseToString

/** Used as references for various `Number` constants. */
// Generate INFINITY, backward compatible
const INFINITY = 1 / 0

/** Used to convert symbols to primitives and strings. */
/ / save Symbol. Prototype. ToString references
const symbolToString = Symbol.prototype.toString

/** * The base implementation of `toString` which doesn't convert nullish * values to empty strings. * The basic toString method does not convert an invalid value to an empty string *@private
 * @param {*} value The value to process.
 * @returns {string} Returns the string.
 */
function baseToString(value) {
  // Exit early for strings to avoid a performance hit in some environments.
  // Do typeof value === 'string' at the beginning to ensure that in most cases value is returned directly
  if (typeof value === 'string') {
    return value
  }
  // array, recursively calls baseToString. May cause a stack overflow
  if (Array.isArray(value)) {
    // Recursively convert values (susceptible to call stack limits).
    return `${value.map(baseToString)}`
  }
  / / symbol type, called symbol. Prototype. ToString returns a string type of symbol value
  // Symbol('x') => 'x'. Otherwise an empty string is returned
  if (isSymbol(value)) {
    return symbolToString ? symbolToString.call(value) : ' '
  }
  ${-0} '=== = '0' true
  const result = `${value}`
  // -0 === 0 true
  // Object.is(0, -0) false
  // Handle the -0 case extra
  return (result === '0' && (1 / value) === -INFINITY) ? '0' : result
}
Copy the code

baseToNumber


/** Used as references for various `Number` constants. */
const NAN = 0 / 0

/** * The base implementation of `toNumber` which doesn't ensure correct * conversions of binary, hexadecimal, Or octal string values. * the basic implementation of 'toNumber' does not ensure the correct conversion of binary, hexadecimal, or octal string values * *@private
 * @param {*} value The value to process.
 * @returns {number} Returns the number.
 */
function baseToNumber(value) {
  // Number type is returned directly
  if (typeof value === 'number') {
    return value
  }
  // symbol type returns NAN
  if (isSymbol(value)) {
    return NAN
  }
  // Otherwise use native toNumber for conversion
  return +value
}
Copy the code

NaN, +undefined can also be generated

isSymbol

function isSymbol(value) {
  // Save a reference to typeof Value
  const type = typeof value
  / / to use typeof judgment, es2015, earlier versions used Object. The prototype. ToString judgment
  return type == 'symbol' || (type === 'object'&& value ! =null && getTag(value) == '[object Symbol]')}Copy the code

typeof Symbol === 'function' typeof Symbol('xx') === 'symbol'

getTag

const toString = Object.prototype.toString

/**
 * Gets the `toStringTag` of `value`.
 *
 * @private
 * @param {*} value The value to query.
 * @returns {string} Returns the `toStringTag`.
 */
function getTag(value) {
  if (value == null) {
    return value === undefined ? '[object Undefined]' : '[object Null]'
  }
  return toString.call(value)
}
Copy the code

Save the Object. The prototype. ToString references.

Use == null == undefined. Value = = null judgments in order to deal with the compatibility issues, since JavaScript 1.8.5 calls to null Object. The prototype. ToString returns (Object null). Calls to undefined Object. The prototype. ToString returns [Object undefined]

By changing the Object’s [Symbol toStringTag] can modify the Object. The prototype. ToString return values