详解JavaScript中任意两数加减的解决方案

目录
  • 写在前面
  • 分析填坑思路
  • 解决整数加减的坑
  • 转换科学计算
  • 解决整数减法的坑
  • 解决小数加法的坑
  • 解决小数减法的坑
  • 解决整数加小数的通用问题
  • 总结

写在前面

本文是从初步解决到最终解决的思路,文章篇幅较长

虽然是一篇从0开始的文章,中间的思维跳跃可能比较大

代码的解析都在文章的思路分析和注释里,全文会帮助理解的几个关键词

1.Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER

2.15长度的字符串

3.padStart 和 padEnd

分析填坑思路

相信很多人都知道这是怎么回事吧

console.log( 0.1 + 0.2 === 0.3 )   // false
console.log( 0.3 - 0.2 === 0.1)   // false

不了解的出门右拐自己去查询下,这里就不一一解释了!

通过上面的例子可以知道,小数点的加减是存在问题的,那么有什么解决方式呢?

既然小数点加减有问题,那就先来整数进行加减吧,这个应该就没什么问题了小数点的加减自行百度解决,可以通过浮点计算,这里就不介绍了,那么整数的加减就一定没有任何问题吗?来看看下面的例子

const MAX = Number.MAX_SAFE_INTEGER;
console.log( MAX )
// 9007199254740991
console.log( MAX + 2 )
// 9007199254740992

Number.MAX_SAFE_INTEGER是什么?

常量表示在 JavaScript 中最大的安全整数

所以,Number.MIN_SAFE_INTEGER就是最小安全系数

顾名思义,就是在JavaScript中加减法在这两个范围内是稳定的,是不是这样就安全了?好像还是有点小问题:

console.log( 10**21 )
// 1e+21
console.log(9999999999999999)
// 9999999999999999
console.log(99999999999999999)
// 10000000000000000
console.log(999999999999999999999)
// 1e+21

从上面的结果来看,是不安全的

1.最后的结果是科学计数法

2.不知道具体的真实数据是多少

既然数字的显示存在这样的问题,把输入结果和输出结果都用字符串表示

console.log(`${10 ** 21}`)
// '1e+21'
console.log('' + 10 ** 21)
// '1e+21'
console.log((10 ** 21).toString())
// '1e+21'

我们发现即使直接就转换成字符串仍然会显示为科学计数法,那么可以直接输入字符串了,跳过转成字符串的过程

解决整数加减的坑

先分析下可能性

1.输入的数字在安全系数范围内,且计算结果也在安全系数范围内,这种直接输出结果

2.不符合条件1(TODO)

    const MAX = Number.MAX_SAFE_INTEGER;
    const MIN = Number.MIN_SAFE_INTEGER;
    /**
     * @Description: 判断输入的数字是否在javascript的安全系数范围内
     * @param { number } 需要检查的数字
     * @return { boolean }: 返回数字是否为安全的整数
     */
    function isSafeNumber(num) {
      // 即使 num 成了科学计数法也能正确的和 MAX, MIN 比较大小
      return MIN <= num && num <= MAX;
    }
    /**
     * @Description: 计算两个数之和,返回计算结果
     * @param { String }: a 相加的第一个整数字符串
     * @param { String }: b 相加的第一个整数字符串
     * @return { string }: 返回计算结果
     */
    function IntAdd(a = "", b = "") {
      let result = "0";
      const intA = Number(a),
        intB = Number(b);
      if (intA === 0) return intB;
      if (intB === 0) return intA;
      if (
        isSafeNumber(intA) &&
        isSafeNumber(intB) &&
        isSafeNumber(intA + intB)
      ) {
        result = intA + intB;
      } else {
        result = IntCalc(a, b);
      }
      return result;
    }
    function IntCalc(a, b) {
      // TODO
    }
    function resClick() {
      const a = document.getElementById("ipt1").value;
      const b = document.getElementById("ipt2").value;
      const result = IntAdd(a, b);
      document.getElementById("res").innerText = result;
    }

如果不满足上面条件的呢?

思路

获取数字转成字符串拆分成多个部分(数组),每一个部分的长度为 Number.MAX_SAFE_INTEGER 转成字符串后的长度减一(15),长度不足15的用字符‘0’填充首部,再计算每个部分的结果后拼接在一起

同时考虑到正负号的问题,拆分后的计算需要带上符号

长度减一的原因是接下来每部分的所有计算都是安全的,不需要在考虑是数字计算结果为安全的整数

同时每部分计算后的结果存在问题以及解决方案

注意:下面会使用15这个数字,15上面说过了,是Number.MAX_SAFE_INTEGER的长度减一

1.计算结果为0

那么这个部分赋值15个字符‘0’组成的字符串,即‘000000000000000’

2.计算结果为负数

那么向上一级数组借10的15次方,同时高位(下一级数组)减一,低位用10的15次方再加上这个负数,做为这个部分的结果

3.计算结果为正数,判断长度:

如果长度超过15,那么去掉结果的第一位字符(因为进位,第一个字符一定是‘1’),同时高位(下一级数组)加一

如果长度没有超过15,向首部补充0直到长度足够15

如果长度等于15,直接添加到结果中

改造上面的代码:

    const MAX = Number.MAX_SAFE_INTEGER;
    const MIN = Number.MIN_SAFE_INTEGER;
    const intLen = `${MAX}`.length - 1;
    /**
     * @Description: 判断输入的数字是否在javascript的安全系数范围内
     * @param { number } 需要检查的数字
     * @return { boolean }: 返回数字是否为安全的整数
     */
    function isSafeNumber(num) {
      // 即使 num 成了科学计数法也能正确的和 MAX, MIN 比较大小
      return MIN <= num && num <= MAX;
    }
    /**
     * @Description: 计算两个数之和,返回计算结果
     * @param { String }: a 相加的第一个整数字符串
     * @param { String }: b 相加的第一个整数字符串
     * @return { string }: 返回计算结果
     */
    function IntAdd(a = "", b = "") {
      const statusObj = checkNumber(a, b);
      if (!statusObj.status) {
        return statusObj.data;
      } else {
        const tagA = Number(a) < 0,
          tagB = Number(b) < 0;
        const strA = `${a}`,
          strB = `${b}`;
        const lenA = tagA ? strA.length - 1 : strA.length;
        const lenB = tagB ? strB.length - 1 : strB.length;
        const maxLen = Math.max(lenA, lenB);
        const padLen = Math.ceil(maxLen / intLen) * intLen; // 即为会用到的整个数组长度
        const newA = tagA
          ? `-${strA.slice(1).padStart(padLen, "0")}`
          : strA.padStart(padLen, "0");
        const newB = tagB
          ? `-${strB.slice(1).padStart(padLen, "0")}`
          : strB.padStart(padLen, "0");
        let result = IntCalc(newA, newB);
        // 去掉正负数前面无意义的字符 ‘0'
        const numberResult = Number(result);
        if (numberResult > 0) {
          while (result[0] === "0") {
            result = result.slice(1);
          }
        } else if (numberResult < 0) {
          while (result[1] === "0") {
            result = "-" + result.slice(2);
          }
        } else {
          result = "0";
        }
        return result;
      }
    }
    function IntCalc(a, b) {
      let result = "0";
      const intA = Number(a),
        intB = Number(b);
      // 判断是否为安全数,不为安全数的操作进入复杂计算模式
      if (
        isSafeNumber(intA) &&
        isSafeNumber(intB) &&
        isSafeNumber(intA + intB)
      ) {
        result = `${intA + intB}`;
      } else {
        const sliceA = a.slice(1),
          sliceB = b.slice(1);
        if (a[0] === "-" && b[0] === "-") {
          // 两个数都为负数,取反后计算,结果再取反
          result = "-" + calc(sliceA, sliceB, true);
        } else if (a[0] === "-") {
          // 第一个数为负数,第二个数为正数的情况
          const newV = compareNumber(sliceA, b);
          if (newV === 1) {
            // 由于 a 的绝对值比 b 大,为了确保返回结果为正数,a的绝对值作为第一个参数
            result = "-" + calc(sliceA, b, false);
          } else if (newV === -1) {
            // 道理同上
            result = calc(b, sliceA, false);
          }
        } else if (b[0] === "-") {
          // 第一个数为正数,第二个数为负数的情况
          const newV = compareNumber(sliceB, a);
          if (newV === 1) {
            // 由于 b 的绝对值比 a 大,为了确保返回结果为正数,b的绝对值作为第一个参数
            result = "-" + calc(sliceB, a, false);
          } else if (newV === -1) {
            // 道理同上
            result = calc(a, sliceB, false);
          }
        } else {
          // 两个数都为正数,直接计算
          result = calc(a, b, true);
        }
      }
      return result;
    }
    /**
     * @Description: 比较两个整数字符串是否正确
     * @param { string }: 比较的第一个整数字符串
     * @param { string }: 比较的第一个整数字符串
     * @return { object }: 返回是否要退出函数的状态和退出函数返回的数据
     */
    function checkNumber(a, b) {
      const obj = {
        status: true,
        data: null
      };
      const typeA = typeof a,
        typeB = typeof b;
      const allowTypes = ["number", "string"];
      if (!allowTypes.includes(typeA) || !allowTypes.includes(typeB)) {
        console.error("参数中存在非法的数据,数据类型只支持 number 和 string");
        obj.status = false;
        obj.data = false;
      }
      if (Number.isNaN(a) || Number.isNaN(b)) {
        console.error("参数中不应该存在 NaN");
        obj.status = false;
        obj.data = false;
      }
      const intA = Number(a),
        intB = Number(b);
      if (intA === 0) {
        obj.status = false;
        obj.data = b;
      }
      if (intB === 0) {
        obj.status = false;
        obj.data = a;
      }
      const inf = [Infinity, -Infinity];
      if (inf.includes(intA) || inf.includes(intB)) {
        console.error("参数中存在Infinity或-Infinity");
        obj.status = false;
        obj.data = false;
      }
      return obj;
    }
    /**
     * @Description: 比较两个整数字符串正负
     * @param { string } a 比较的第一个整数字符串
     * @param { string } b 比较的第二个整数字符串
     * @return { boolean } 返回第一个参数与第二个参数的比较
     */
    function compareNumber(a, b) {
      if (a === b) return 0;
      if (a.length > b.length) {
        return 1;
      } else if (a.length < b.length) {
        return -1;
      } else {
        for (let i = 0; i < a.length; i++) {
          if (a[i] > b[i]) {
            return 1;
          } else if (a[i] < b[i]) {
            return -1;
          }
        }
      }
    }

    /**
     * @Description: 相加的结果
     * @param { string } a 相加的第一个整数字符串
     * @param { string } b 相加的第二个整数字符串
     * @param { string } type 两个参数是 相加(true) 还是相减(false)
     * @return { string } 返回相加的结果
     */
    function calc(a, b, type = true) {
      const arr = []; // 保存每个部分计算结果的数组
      for (let i = 0; i < a.length; i += intLen) {
        // 每部分长度 15 的裁取字符串
        const strA = a.slice(i, i + intLen);
        const strB = b.slice(i, i + intLen);
        const newV = Number(strA) + Number(strB) * (type ? 1 : -1); // 每部分的计算结果,暂时不处理
        arr.push(`${newV}`);
      }
      let num = ""; // 连接每个部分的字符串
      for (let i = arr.length - 1; i >= 0; i--) {
        if (arr[i] > 0) {
          // 每部分结果大于 0 的处理方案
          const str = `${arr[i]}`;
          if (str.length < intLen) {
            // 长度不足 15 的首部补充字符‘0'
            num = str.padStart(intLen, "0") + num;
          } else if (str.length > intLen) {
            // 长度超过 15 的扔掉第一位,下一部分进位加一
            num = str.slice(1) + num;
            if (i >= 1 && str[0] !== "0") arr[i - 1]++;
            else num = "1" + num;
          } else {
            // 长度等于 15 的直接计算
            num = str + num;
          }
        } else if (arr[i] < 0) {
          // 每部分结果小于 0 的处理方案,借位 10的15次方计算,结果恒为正数,首部填充字符‘0'到15位
          const newV = `${10 ** intLen + Number(arr[i])}`;
          num = newV.padStart(intLen, "0") + num;
          if (i >= 1) arr[i - 1]--;
        } else {
          // 每部分结果等于 0 的处理方案,连续15个字符‘0'
          num = "0".padStart(intLen, "0") + num;
        }
      }
      return num;
    }

测试结果:

全部代码请点击 这里

console.log(MAX)  // 9007199254740991
intAdd(MAX, '2')  // '9007199254740993'
intAdd(MAX, '10000000000000000')  // '19007199254740991'
// 下面测试10的二十一次方的数据 1000000000000000000000
intAdd(MAX, '1000000000000000000000')  // '1000009007199254740991'
intAdd(MAX, `-${10 ** 16}`)  // '-992800745259009'
// 仍然存在一个问题,就是不要使用计算中的字符串,如下
intAdd(MAX, `${10 ** 21}`)  // '10.0000000071992548e+21'
intAdd(MAX, `-${10 ** 21}`)  // '0'

转换科学计算

当然考虑到由于一般计算不会使用大数,书写字符串相加确实感觉怪怪的,可以在函数内加入判断,是科学计数法的提示并转换为10进制数,进行代码改进:

/**
 * @Description: 计算两个数之和,返回计算结果
 * @param { String }: a 相加的第一个整数字符串
 * @param { String }: b 相加的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function intAdd(a = "", b = "") {
  const statusObj = checkNumber(a, b);
  if (!statusObj.status) {
    return statusObj.data;
  } else {
    let newA, newB, maxLen;
    const tagA = Number(a) < 0,
      tagB = Number(b) < 0;
    let strA = `${a}`,
      strB = `${b}`;
    const reg = /^\-?(\d+)(\.\d+)?e\+(\d+)$/;
    if (reg.test(a) || reg.test(b)) {
      console.warn(
        "由于存在科学计数法,计算结果不一定准确,请转化成字符串后计算"
      );
      strA = strA.replace(reg, function(...rest) {
        const str = rest[2] ? rest[1] + rest[2].slice(1) : rest[1];
        return str.padEnd(Number(rest[3]) + 1, "0");
      });
      strB = strB.replace(reg, function(...rest) {
        const str = rest[2] ? rest[1] + rest[2].slice(1) : rest[1];
        return str.padEnd(Number(rest[3]) + 1, "0");
      });
      maxLen = Math.max(a.length, b.length);
    } else {
      const lenA = tagA ? strA.length - 1 : strA.length;
      const lenB = tagB ? strB.length - 1 : strB.length;
      maxLen = Math.max(lenA, lenB);
    }
    const padLen = Math.ceil(maxLen / intLen) * intLen; // 即为会用到的整个数组长度
    newA = tagA
      ? `-${strA.slice(1).padStart(padLen, "0")}`
      : strA.padStart(padLen, "0");
    newB = tagB
      ? `-${strB.slice(1).padStart(padLen, "0")}`
      : strB.padStart(padLen, "0");
    let result = intCalc(newA, newB);
    // 去掉正负数前面无意义的字符 ‘0'
    const numberResult = Number(result);
    if (numberResult > 0) {
      while (result[0] === "0") {
        result = result.slice(1);
      }
    } else if (numberResult < 0) {
      while (result[1] === "0") {
        result = "-" + result.slice(2);
      }
    } else {
      result = "0";
    }
    console.log(result);
    return result;
  }
}

解决整数减法的坑

加法和减法同理,只需要把第二个参数取反后利用加法运算就可以了,由于之前已经提取了模板,可以直接定义减法函数

/**
 * @Description: 整数减法函数入口
 * @param { String }: a 减法的第一个整数字符串
 * @param { String }: b 减法的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function intSub(a = "0", b = "0") {
  const newA = `${a}`;
  const newB = Number(b) > 0 ? `-${b}` : `${b}`.slice(1);
  const result = intAdd(newA, newB);
  return result;
}

测试结果

全部代码请点击 这里

intSub('9037499254750994', '-9007299251310995')
// 18044798506061989

解决小数加法的坑

文章开头说了,小数加减,可以通过浮点进行计算,但是这里既然完成了整数的加减,那么能不能利用整数的加减原理来解决小数的加减计算呢?

  • 整数加法代码中经常出现 padStart 这个向前补齐的函数,因为在整数前加字符‘0’的对本身没有影响。
  • 小数也有这个原理,往尾部补‘0’同样对小数没有影响,然后再补齐后的数通过整数加减来计算。

首先来看下小数的加法计算实现

/**
 * @Description: 小数加法函数入口
 * @param { String }: a 相加的第一个整数字符串
 * @param { String }: b 相加的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function floatAdd(a = "0", b = "0") {
  const statusObj = checkNumber(a, b);
  if (!statusObj.status) {
    return statusObj.data;
  } else {
    const strA = `${a}`.split("."),
      strB = `${b}`.split(".");
    let newA = strA[1],
      newB = strB[1];
    const maxLen = Math.max(newA.length, newB.length);
    const floatLen = Math.ceil(maxLen / intLen) * intLen;
    newA = newA.padEnd(floatLen, "0");
    newB = newB.padEnd(floatLen, "0");
    newA = strA[0][0] === "-" ? `-${newA}` : newA;
    newB = strB[0][0] === "-" ? `-${newB}` : newB;
    let result = intCalc(newA, newB);
    let tag = true,
      numResult = Number(result);
    // 去掉正负数后面无意义的字符 ‘0'
    if (numResult !== 0) {
      if (numResult < 0) {
        result = result.slice(1);
        tag = false;
      }
      result =
        result.length === floatLen ? `0.${result}` : `1.${result.slice(1)}`;
      result = tag ? result : `-${result}`;
      let index = result.length - 1;
      while (result[index] === "0") {
        result = result.slice(0, -1);
        index--;
      }
    } else {
      result = "0";
    }
    console.log(result);
    return result;
  }
}

测试结果

floatAdd('0.9037499254750994', '-0.9007299251310995')
// 0.0030200003439999

解决小数减法的坑

与整数减法的原理相同,可以直接定义减法函数

/**
 * @Description: 小数减法函数入口
 * @param { String }: a 相减的第一个整数字符串
 * @param { String }: b 相减的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function floatSub(a = '0', b = '0') {
  const newA = `${a}`
  const newB = Number(b) > 0 ? `-${b}`: `${b.slice(1)}`
  const result = floatAdd(newA, newB)
  return result
}

测试结果

全部代码请点击 这里

floatSub('0.9037499254750994', '-0.9007299251310995')
// 1.8044798506061989

解决整数加小数的通用问题

其实在实际开发过程中,并不是整数相加减,小数相加减,都有可能出现,所以还要考虑整数与小数之间的加减计算

这里的解决思路仍然是往前补0和往后补0

把整数和小数都补充完整后,合在一起进行整数相加

最后根据之前保存的整数的长度,插入小数点

剩下的就是把无意义的0排除掉,输出结果

/**
 * @Description: 计算两个数之差,返回计算结果
 * @param { String }: a 相减的第一个整数字符串
 * @param { String }: b 相减的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function allSub(a = "0", b = "0") {
  const newA = `${a}`;
  const newB = Number(b) > 0 ? `-${b}` : `${b}`.slice(1);
  const result = allAdd(newA, newB);
  return result;
}
/**
 * @Description: 计算两个数之和,返回计算结果
 * @param { String }: a 相加的第一个整数字符串
 * @param { String }: b 相加的第一个整数字符串
 * @return { string }: 返回计算结果
 */
function allAdd(a = "0", b = "0") {
  const statusObj = checkNumber(a, b);
  if (!statusObj.status) {
    return statusObj.data;
  } else {
    const strA = `${a}`.split("."),
      strB = `${b}`.split(".");
    let intAs = strA[0],
      floatA = strA.length === 1 ? "0" : strA[1];
    let intBs = strB[0],
      floatB = strB.length === 1 ? "0" : strB[1];
    // 可能存在纯整数 或者纯小数 0.xxxxxxx
    const tagA = intAs > 0 || !intAs[0] === '-' || intAs[0] === '0',
      tagB = intBs > 0 || !intBs[0] === '-' || intBs[0] === '0';
    const maxIntLen = Math.max(intAs.length, intBs.length);
    const arrIntLen = Math.ceil(maxIntLen / intLen) * intLen;
    const maxFloatLen = Math.max(floatA.length, floatB.length);
    const arrFloatLen = Math.ceil(maxFloatLen / intLen) * intLen;
    intAs = tagA
      ? intAs.padStart(arrIntLen, "0")
      : intAs.slice(1).padStart(arrIntLen, "0");
    intBs = tagB
      ? intBs.padStart(arrIntLen, "0")
      : intBs.slice(1).padStart(arrIntLen, "0");
    let newA =
      floatA === "0"
        ? intAs + "0".padEnd(arrFloatLen, "0")
        : intAs + floatA.padEnd(arrFloatLen, "0");
    let newB =
      floatB === "0"
        ? intBs + "0".padEnd(arrFloatLen, "0")
        : intBs + floatB.padEnd(arrFloatLen, "0");
    newA = tagA ? newA : `-${newA}`;
    newB = tagB ? newB : `-${newB}`;
    let result = intCalc(newA, newB);
    const numResult = Number(result);
    if (result.length > arrIntLen) {
      result = result.slice(0, -arrFloatLen) + "." + result.slice(arrFloatLen);
    }
    // 去掉正负数前面后面无意义的字符 ‘0'
    if (numResult !== 0) {
      if (numResult > 0) {
        while (result[0] === "0") {
          result = result.slice(1);
        }
      } else if (numResult < 0) {
        while (result[1] === "0") {
          result = "-" + result.slice(2);
        }
        result = result.slice(1);
        tag = false;
      }
      let index = result.length - 1;
      while (result[index] === "0") {
        result = result.slice(0, -1);
        index--;
      }
    } else {
      result = "0";
    }
    if (result[result.length - 1] === ".") {
      result = result.slice(0, -1);
    }
    if (result[0] === ".") {
      result = "0" + result;
    }
    console.log(result);
    return result;
  }
}

测试结果

全部代码请点击 这里

allAdd("9037499254750994", "0.9007299251310995");
// 9037499254750994.9007299251310995
allSub("9037499254750994", "-0.9007299251310995");
// 9037499254750994.9007299251310995
allAdd('9037499254750994.9037499254750994', '-9007299251310995.9007299251310995');
// 30200003439999.0030200003439999
allSub('9037499254750994.9037499254750994', '9007299251310995.9007299251310995');
// 30200003439999.0030200003439999

总结

Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 之间的计算才是可信任的

小数加减的浮点精度问题转移到整数来解决

超大的数加减的时候,分区计算(理由是第1点)

拆分成每部分15长度的字符串(理由是Number.MAX_SAFE_INTEGER的长度为16,无论如何加减都是满足第一点的,这样就不需要去注意加减的安全性问题了)

科学计数法的问题,匹配是否为科学计数法的数,然后转换成十进制,同时提出警告,因为科学计数法的数存在误差,计算会存在不准确性

以上就是详解JavaScript中任意两数加减的解决方案的详细内容,更多关于JavaScript数字加减的资料请关注我们其它相关文章!

(0)

相关推荐

  • js浮点数精确计算(加、减、乘、除)

    复制代码 代码如下: <SPAN style="FONT-SIZE: 18px">//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精确的加法结果.   //调用:accAdd(arg1,arg2)   //返回值:arg1加上arg2的精确结果   function accAdd(arg1,arg2){      var r1,r2,m;      try{r1=arg1.toString().split(".&

  • javascript解决小数的加减乘除精度丢失的方案

    原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3*1 = 0.2999999999等,下面列出可以完美求出相应精度的四种js算法 function accDiv(arg1,arg2){ var t1=0,t2=0,r1,r2; try{t1=arg1.toString().split(".")[1].length}catch(e){} t

  • js 时间函数应用加、减、比较、格式转换的示例代码

    复制代码 代码如下: // JavaScript Document //--------------------------------------------------- // 判断闰年 //--------------------------------------------------- Date.prototype.isLeapYear = function() { return (0==this.getYear()%4&&((this.getYear()%100!=0)||(

  • js用Date对象的setDate()函数对日期进行加减操作

    想自己写一个日期的加减方法,但是涉及到每个月天数的判断,如果是2月份的话,还要涉及到闰年的判断,有些复杂,应用过程中总是出现问题,于是查了下资料,以在某个日期上加减天数来说,其实只要调用Date对象的setDate()函数就可以了,具体方法如下: function addDate(date,days){ var d=new Date(date); d.setDate(d.getDate()+days); var month=d.getMonth()+1; var day = d.getDate(

  • js实现网页的两个input标签内的数值加减(示例代码)

    实例如下所示: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script> window.onload=function(){ var oIput1=document.getElementById('put1'); var oIput2=document.getElementById('put2'); var

  • 详解JavaScript中任意两数加减的解决方案

    目录 写在前面 分析填坑思路 解决整数加减的坑 转换科学计算 解决整数减法的坑 解决小数加法的坑 解决小数减法的坑 解决整数加小数的通用问题 总结 写在前面 本文是从初步解决到最终解决的思路,文章篇幅较长 虽然是一篇从0开始的文章,中间的思维跳跃可能比较大 代码的解析都在文章的思路分析和注释里,全文会帮助理解的几个关键词 1.Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 2.15长度的字符串 3.padStart 和 padEnd 分析填坑思

  • 详解JavaScript中的执行上下文及调用堆栈

    一.执行上下文是什么 代码运行是在一定的环境之中运行的,这个运行环境我们就成为执行环境,也就是执行上下文,按照执行环境不同,我们可以分为三类: 全局执行环境:代码首次执行时候的默认环境 函数执行环境:每当执行流程进入到一个函数体内部的时候 Eval执行环境:当eval函数内部的文本执行的时候 二.执行上下文栈是什么 既然是'栈',那就得符合'栈'的特性,即数据结构是先进后出.下面我们看一段代码: function cat(a){ if(a<0){ return false; } console.

  • 详解Javascript中prototype属性(推荐)

    在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不是基于'类的',而是通过构造函数(constructor)和原型链(prototype chains)实现的.但是在ES6中提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板.通过class关键字,可以定义类.基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能

  • 详解Javascript 中的 class、构造函数、工厂函数

    到了ES6时代,我们创建对象的手段又增加了,在不同的场景下我们可以选择不同的方法来建立.现在就主要有三种方法来构建对象,class关键字,构造函数,工厂函数.他们都是创建对象的手段,但是却又有不同的地方,平时开发时,也需要针对这不同来选择. 首先我们来看一下,这三种方法是怎样的 // class 关键字,ES6新特性 class ClassCar { drive () { console.log('Vroom!'); } } const car1 = new ClassCar(); consol

  • 详解JavaScript中Arguments对象用途

    目录 前言 Arguments 的基本概念 Arguments 的作用 获取实参和形参的个数 修改实参值 改变实参的个数 检测参数合法性 函数的参数个数不确定时,用于访问调用函数的实参值 遍历或访问实参的值 总结 在实际开发中,Arguments 对象非常有用.灵活使用 Arguments 对象,可以提升使用函数的灵活性,增强函数在抽象编程中的适应能力和纠错能力. JavaScript 中 Arguments 对象的用途总结. 前言 相信我们很多人在代码开发的过程中都使用到过一个特殊的对象 --

  • 详解javaScript中Number数字类型的使用

    目录 前言 Number数字 自带属性值 基础使用 总结 源码地址 前言 Number和Math都属于JavaScript中的内置对象,Number数字类型作为基础数据类型,我们在开发过程中会经常用到,包括数字精度的格式化,还有字符串转换成数字等操作. Number数字 自带属性值 Number.EPSILON 两个可表示(representable)数之间的最小间隔. Number.MAX_SAFE_INTEGER JavaScript 中最大的安全整数 (2^53 - 1). Number.

  • 详解JavaScript中的变量命名规范

    目录 驼峰命名 根据变量类型来命名 普通变量/属性 布尔变量/属性 普通函数/方法 回调.钩子函数 类 注意一致性 介词一致性 顺序一致性 表里一致性 时间一致性 其他注意事项 避免使用不常用的缩写 避免使用容易混淆的字母和数字 避免变量命名过于抽象 驼峰命名 首先,和其他语言一样,大部分变量建议采用驼峰命名法. var articleTitle = 'javascript变量命名规范' 而对于常量,使用大写字母和下划线来组合命名. const COUNTRY_NAME = 'China' 根据

  • 详解JavaScript中的Object.is()与"==="运算符总结

    三重相等运算符 === 严格检查2个值是否相同: 1 === 1; // => true 1 === '1'; // => false 1 === true; // => false 但是,ES2015规范引入了 Object.is(),其行为与严格的相等运算符几乎相同: Object.is(1, 1); // => true Object.is(1, '1'); // => false Object.is(1, true); // => false 主要问题是:什么时

  • 详解JavaScript中的this指向问题

    题记 JS中的this指向一直是个让初学者头疼的问题.今天,我们就一起来瞅瞅this倒地是咋回事,详细说说this指向原则,从此不再为了this指向操碎了心. 开篇 首先我们都知道this是Javascript语言的一个关键字. 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它所在函

  • 详解JavaScript中new操作符的解析和实现

    前言 new 运算符是我们在用构造函数创建实例的时候使用的,本文来说一下 new 运算符的执行过程和如何自己实现一个类似 new 运算符的函数. new 运算符的运行过程 new 运算符的主要目的就是为我们创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例(比如箭头函数就没有构造函数,所以是不能 new 的).new 操作符的执行大概有以下几个步骤: 创建一个新的空对象 把新对象的 __proto__ 链接到构造函数的 prototype 对象(每一个用户定义函数都有一个 proto

随机推荐