欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Javascript的一些坑点

程序员文章站 2022-07-15 15:45:29
...

在使用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.1	// 0.19999999999999998
0.1 * 0.2 不等于0.02		//0.020000000000000004

解决办法1parseFloat((5/3).toPrecision(12)) 来解决绝大部分的0.0..010.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;
    } 
}

打印结果为[ [ 3, 6, 9 ], [ 3, 6, 9 ], [ 3, 6, 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列的元素