Recently, I used the method with high frequency in the summary work. Because the project often involves numbers such as traffic and money, I thought of a standard method to unify the numbers displayed on the front page to meet the various needs of the product. Boy, that’s a hell of a hole to write about.

/** * Complete Boolean, Null, String to type Number, And support to take up the whole, whole, rounded down reserves the specified digital * @ param {Boolean | | Null | | String | | Number} val transformation target * @ param {Number} precision digital precision, * @param {String} A maximum of 9 decimal digits are supported.typeRound is rounded by default, while ceiL is rounded up and floor is rounded down * @return*/ const toNumber = (val, precision=2,type='round') => {// to be filled}Copy the code

My journey:

  1. Filter out data types that cannot be converted to significant numbers. The most overbearing method is Number(), and the surprise is that Number([]) prints 0!! So what do the six primitive types + Object output as arguments to Number? (The following results run on the official 64-bit version of Chrome V73.0.3683.86)
  • Boolean
  • Null
  • Undefined
  • After all, Number is one, so I’m not going to verify it
  • String
  • Symbol (so the question is: What is a Symbol?)
  • Object

    array

    function

    date

    math

    RegExp







    (Then the question arises: How Number is handled)

    From the above we can see that although arrays and dates may return numbers as arguments to Number(), from a production perspective this is simply too… . Boolean, Null, String, Number (String, Number);

const toNumber = (val, precision=2, type='round') => {// Exclude non-boolean, Null, String, Number types // typeof Null ==='object'
  if(typeof val ! = ='boolean'&& typeof val ! = ='string'&& typeof val ! = ='number'&& val ! == null) {returnNull} // removes input that is a string but cannot be parsed to a numberif (typeof val === 'string' && isNaN(Number(val))) {
    returnNull} // to be filled}Copy the code
  1. Pit – toFixed

    Before that, the internal front end of the company used toFixed method for handling money, but this method, you know…

    ToFixed () is rumored to use the banker algorithm, i.e“Round four six into fifty.”: here “four” refers to ≤4, “six” refers to ≥6, “five” refers to according to the number behind 5, when 5 is several, rounding 5 into 1; If there is no significant digit after 5, we need to divide it into two cases: ① If 5 is an odd number before 5, rounding 5 to 1; ② If 5 is an even number (including 0), it cannot be rounded by 5. But the actual result of the run does not follow this rule completely (the red box is not consistent with the change rule) :

    How exactly does toFixed() work? ECMAScript 3rd Edition (ECMA-262)English version references address.Chinese version references address) shall have the following process (take Chinese version as an example) :

    I was so successful…

    To sum up:Avoid toFixed as much as possible

  2. Pit – floating point precision is well known, 0.1+0.2! ==0.3, why greasy?
Binary representation of 0.1:0.000110011...... 0011... (0011 infinite loop) binary representation of 0.2:0.00110011...... 0011... (0011 Infinite loop)Copy the code

The number of computer storage is limited, so for this infinite cycle of numbers is not accurate storage, rounding has 0.1+0.2! ==0.3 the fact that goes against the facts. For the specific calculation principle, please refer to how to avoid the calculation accuracy problem of JavaScript floating point number (such as 0.1+0.2! This function is represented as a string of a numeric object in either fixed-point or exponential notation, rounded to the number of digits displayed as specified by the precision argument. Note that precision is calculated from the first non-zero digit from left to right. In addition, when the corresponding digit is an integer multiple of 10 and greater than 1, the returned result will be expressed in the scientific and technical method:








/** * Complete Boolean, Null, String to type Number, And support to take up the whole, whole, rounded down reserves the specified digital * @ param {Boolean | | Null | | String | | Number} val transformation target * @ param {Number} precision digital precision, * @param {String} A maximum of 9 decimal digits are supported.typeRound is rounded by default, while ceiL is rounded up and floor is rounded down * @return*/ const toNumber = (val, precision=2,type='round') => {// Exclude non-boolean, Null, String, Number types // typeof Null ==='object'
  if(typeof val ! = ='boolean'&& typeof val ! = ='string'&& typeof val ! = ='number'&& val ! == null) { throw('toNumber() can not convert val argument to number'} // remove inputs that are strings but cannot be parsed to numbersif (typeof val === 'string' && isNaN(Number(val))) {
    throw('toNumber() can not convert val argument to number'} // Verify precision type and size: according to the experience of the project, first satisfy is a numeric type, an integer between 0 and 9let reg = /^\d{1}$/
  if(typeof precision ! = ='number'| |! reg.test(precision)) { throw('toNumber() precision argument must be Integer and between 0 and 9'} // checktypeConst types = ['round'.'ceil'.'floor']
  if(! types.includes(type)) {
    throw('toNumber() type argument must be one of "round", "ceil", "floor"')}letTarget = math.floor (Number(val)) + Number((Number(val) % 1).toprecision (12)) // Handle symbol bitslet target_s = target < 0 ? The '-' : ' '
  target = target < 0 ? -1 * target : target

  let multiple = Math.pow(10, precision - 0)
  if (type= = ='ceil') {
    target = Math.ceil(target * multiple) / multiple
  } else if (type= = ='floor') {
    target = Math.floor(target * multiple) / multiple
  } else{target = math.round (target * multiple)/multiple} target = target.tostring () // handle decimal partslet target_int = target.includes('. ')? target.split('. ')[0] : target
  let target_decimal = target.includes('. ')? target.split('. ') [1] :' '

  if (target_decimal.length < precision) {
    for (let i = 0; i < precision; i++) {
      target_decimal = target_decimal + '0'
      if (target_decimal.length === precision) {
        break}}}return target_s + target_int + (precision > 0 ? '. ' + target_decimal : ' ')}Copy the code

If there is any wrong please criticize and correct, which god has a better way please advise