Javascript的一些坑点

在使用JS进行程序设计时,偶尔会遇到最终的结果与预期不同的情形,我将导致这种情况的因素称为坑点。

1、Array.prototype.sort([fn])

需要对数组原地稳定排序时,可以使用 arr.sort(fn), 但别忘了指定排序规则函数fn(a,b),否则会按元素的unicode码大小升序排序,如[1,2,10] => [1,10,2]

2、Number类型运算

js中无整数,只有IEEE754标准的双精度64位浮点数,因此做加减乘除运算的时候会很坑:

// 第一个坑点
0.1 + 0.2 不等于 0.3       // 0.30000000000000004
0.3 -0.1 不等于 0.2    // 0.19999999999999998
0.1 * 0.2 不等于0.02       //0.020000000000000004

解决办法1是 parseFloat((5/3).toPrecision(12)) 来解决绝大部分的0.0..01和0.99.。99

解决办法2是 将小数转化成整数,再运算,再转换成小数。

当需要求一个被除数与除数的商和余数时,千万别套用C++的那一套

// C++
int a = 5/3;   // 1
int b = 5%3;   // 2

// JS
let a = 5/3     // 1.6666666666666667
let b = 5%3     // 2

解决办法是向下取整 let a = Math.floor(5/3); // 适用于求商,其他运算以此类推

3、引用类型

拿数组举例,当回溯过程中需要用到数组来返回结果时:

function ruc(arr, res) {
    if(end_situation) res.push(arr);
    ...
    ruc(arr);
    ...
}

如果这样写的话,最后结果毫无意外一定是

[[],[],[],...,[]]
或者
[[same],[same],...,[same]]

所以需要在传递前做一次 仅适合于一维数组的深拷贝

JSON.parse(JSON.stringify(arr));
or
arr.slice();
or
Object.assign([],arr);

4、二维数组

JS是无法像C++一样直接int arr[][] 或 int * arr[] 创建一个二维数组的,会稍微繁琐些,当我想创建一个1到9的3X3矩阵时:

[   
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

在起初,可能会这样做(错误

let arr = [], num = 0;
for(let i=0;i<3;i++) {
    for(let j=0;j<3;j++) {
        arr[i][j] = ++num;
    } 
}

报错 TypeError: Cannot set property '0' of undefined 很显然,arr[0]是undefined,这种写法不对。

于是改成这样(也是错误

let arr = [], num = 0;
// -------新增代码段开始-----------
let tmp = [];
for(let i=0;i<3;i++) {
    arr.push(tmp);
}
// -------新增代码段结束--------------
for(let i=0;i<3;i++) {
    for(let j=0;j<3;j++) {
        arr[i][j] = ++num;
    } 
}

打印结果为[ [ 7, 8, 9 ], [ 7, 8, 9 ], [ 7, 8, 9 ] ] 很显然,又是引用的问题,有两种解决办法
(1)如第四点所说,在arr.push(tmp)中将tmp深拷贝再传递
(2)改成下面这种写法(正确)

let arr = [], num = 0;
for(let i=0;i<3;i++) {
    let tmp = [];
    for(let j=0;j<3;j++) {
        tmp.push(++num);
    }
    arr.push(tmp); 
}

还可以用(正确

let arr = new Array(3), num = 0;
for(let i=0;i<3;i++) {
    arr[i] = new Array(3);
    for(let j=0;j<3;j++) {
        arr[i][j]= ++num;
    }
}

这种写法和第一种错误写法思路很类似了,使用new Array([size])还能规定长度。

如果想采用ES6来创建,这样写是(错误)的,依旧是引用的问题

let arr = new Array(3).fill(new Array(3));
let num = 0;
for(let i in arr) for(let j in  arr) arr[i][j]=++num;

打印 [ [ 7, 8, 9 ], [ 7, 8, 9 ], [ 7, 8, 9 ] ],
正确做法如下:

let arr = Array.from(Array(3), () => new Array(3))
let num = 0;
for(let i in arr) for(let j in  arr) arr[i][j]=++num;

另外需要留意的是遍历中会有坑的点:
(1)用arr.length取矩阵的高/行数, arr[0].length取矩阵的宽/列数
(2)arr[i][j] 表示 第i个一维数组的第j个元素; 也表示 第ij列的元素

5、运算符优先级

举个例子: 1与2异或等于3,那么按我们的常规思维来说来说 1^2 > 1 应该是得到布尔值true的,但是实际上返回0

1^2 > 1
等价于
1^(2>1)

这是因为运算符优先级左/右关联导致的,需要时查阅MDN运算符优先级
为了避免运算符这个坑,按自己的思路加小括号()强制优先运算即可,如(1^2)> 1

6、Array.prototype.splice(start, delete_cnt, item1, item2, item3, ...)

用splice删除或插入元素时,数组长度会变,在搭配循环使用时需要留意索引的回退等等

for(let i=0;i

你可能感兴趣的:(Javascript的一些坑点)