Skip to content

JS 常见问题解决

new Date 兼容性问题

以下环境 的代码会报错

  • IOS 11.1.2 iphoneX safari
  • IE11
javascript
var d = new Date("2018-09-20 19:20:32"); // invalid date
alert(d.getTime());

必须改成:

javascript
var d = new Date("2018/09/20 19:20:32");
alert(d.getTime());

chrome 浏览器 或者 用 moment.js

javascript
moment("2018-09-20 10:58").valueOf();

后端返回的数字过长, 造成精度丢失问题

假设服务端返回数据如下, 可以看到 JSON.parse 之后精度有丢失。

js
const data = '{"id":12345678901234567890,"name":"David"}';
const res = JSON.parse(data); // {id: 12345678901234567000, name: "David"}

解决方案

1.使用正则将 Long 类型数据转换为字符串

js
axios({
  method: method,
  url: url,
  data: data,
  transformResponse: [
    function (data) {
      const convertedJsonString = data.replace(/"(\w+)":(\d{15,})/g, '"$1":"$2"');
      // '{"id":12345678901234567890,"name":"David"}' 转化成 '{"id":"12345678901234567890","name":"David"}'
      return JSON.parse(convertedJsonString);
    }
  ]
});

2.使用 npm 包 json-bigint处理

js
import JSONbig from "json-bigint";
axios({
  method: method,
  url: url,
  data: data,
  transformResponse: [
    function (data) {
      const JSONbigToString = JSONbig({ storeAsString: true });
      // 将Long类型数据转换为字符串
      return JSONbigToString.parse(data);
    }
  ]
});

try catch

try catch 功能里的 try 里的代码如果是异步的话,在 catch 里捕获不到。

javascript
try {
  throw new Error("sss");
} catch (e) {
  console.log(11111); // 能执行
}
javascript
try {
  setTimeout(() => {
    throw new Error("sss");
  }, 0);
} catch (e) {
  console.log(11111); // 不能执行
}

所以造成 promise 里面的异步回调函数的报错 在 catch 监听不到

javascript
promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw Error("This is an error");
  });
});

promise.catch((error) => {
  console.log(1111); // 不会执行
});

正则表达式 test exec match 里的问题

正则使用 test 和 exec 多次会返回值不一样的情况,match 不会有问题,原因是 RegExp 有一个 lastIndex 属性来保存索引开始位置,第 1 次调用的 lastIndex 值为 0,第 2 次调用 lastIndex 为 1。 解决方案是:

  1. 去掉 g,关闭全局匹配。(但是通常不会关掉)
  2. 每次匹配之前将 lastIndex 的值设置为 0。
javascript
var reg = /1/g;
reg.test("1"); // true
reg.test("1"); // false
reg.exec("1"); // ["1", index: 0, input: "1", groups: undefined]
reg.exec("1"); // null
"1".match(reg); // ["1"]
"1".match(reg); // ["1"]

// 解决方式
reg.lastIndex = 0;
reg.test("1"); // true
reg.lastIndex = 0;
reg.test("1"); // true

String

公司的项目发现 String 下面赋值就报错。

javascript
// Uncaught TypeError: Cannot assign to read only property '0' of object '[object String]'
Object.assign("a", "b");

实际上 string 是 immutable,不能被改变值的。

javascript
var str = "ab";
str[0] = "1111"; // 虽然赋值不会报错
console.log(str); // 'ab'

若要改变可以用, str.replace

javascript
var str = "ab";
var str2 = str.replace("a", "1");
console.log(str2); // '1b'

或者 Object.assign赋值一个空字符串

javascript
var str = Object.assign("", ""); // String {""}
str[0] = "1"; // String {"", 0: "1"}
console.log(str[0]); // 1

或者 用Object.defineProperty

javascript
// 注意这里不能用  var obj = '',
// 否则会报错 Uncaught TypeError: Object.defineProperty called on non-object
var obj = new String();
Object.defineProperty(obj, "a", {
  writable: true,
  value: "1"
});
console.log(obj.a); // 1
obj.a = "2";
console.log(obj.a); // 2

滚动相关

1. 获取滚动条的高度

js
var container = document.querySelector(".container");
var scrollbarHeight = container.scrollHeight - container.clientHeight;

2. 获取一个元素相对于其父级元素的高度

注意 container 必须设置 relative 才可以使用 offsetTop, 否则只能使用 firstChild.getBoundingClientRect().top - container.getBoundingClientRect().top

js
var firstElementChild = document.querySelector(".content").firstElementChild;
firstElementChild.offsetTop;

3. 如果是向下滚动的话

那么最后一个元素是向下滚动 40px, 倒数第 2 个元素是向下滚动 80px;

js
var lastElementChild = document.querySelector(".content").lastElementChild;
var container = document.querySelector(".container");
container.scrollHeight - lastElementChild.offsetTop;

html 代码如下:

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>滚动示例</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      .container {
        margin: 100px;
        width: 300px;
        height: 200px;
        overflow-y: scroll;
        border: 10px solid #000;
        position: relative;
      }
      .content {
      }
      .content div {
        height: 40px;
        border: 1px solid red;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="content">
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
        <div>6</div>
        <div>7</div>
        <div>8</div>
        <div>9</div>
        <div>10</div>
      </div>
    </div>
  </body>
</html>

浏览器原生支持生成 UUID, window.crypto.randomUUID()

是一种用于生成随机 UUID(通用唯一标识符)的方法 兼容性表:

  • Google Chrome: 支持 (自版本 92 起)
  • Mozilla Firefox: 支持 (自版本 95 起)
  • Safari: 支持 (自版本 15.4 起)
  • Microsoft Edge: 支持 (自版本 92 起)
  • Opera: 支持 (自版本 78 起)
js
window.crypto.randomUUID(); //  '7e96031a-9db8-4f8f-aa6b-e55a8d374764'