JavaScript躲坑指南(一)

本系列将会写一些在正常工作中会遇到的一些坑,然后分析它们的产生原因及解决办法.本文的内容主要来自<you don’t know JS>及日常工作的问题的一些总结.

坑一: 关于parseInt()方法转换字符串的问题,神坑!

1
2
3
4
5
6
7
console.log(parseInt(1/0, 19));  //18
//原因:1/0得到的结果是Infinity,而得到的Infinity本身其实也是一个字符串,所以parseInt会以19进制对其进行类型转换,首字母为I,则其结果则为18了.
console.log(parseInt(.000009)) //0
console.log(parseInt(.0000009)) //9
console.log(parseInt(false, 16)) //250,判定'false'的字符串的'fa'为十六进制了
console.log(parseInt(parseInt, 16)) //15
//结果为15的原因是因为parseInt为函数,所以会被typeof为function,

坑二: 位运算符~的妙用:

在许多编程语言中,查找值或函数执行过程中,大于等于0的值表示查找或执行成功,返回-1则表示查找或执行失败.因此当失败时,可以直接使用位运算符~进行判定,当为-1时, -(-1 + 1) 即为零,因此就可以直接进行布尔运算了.

1
2
3
4
var a = "hello world";
if(~a.indexof("lo")){
//查找不到值,则执行函数体中的内容
}

位运算的另一个巧妙用法:将值截除为一个32位整数

1
2
3
4
console.log(Math.floor(-.1))  //-1
console.log(Math.floor(.1)) //0
console.log(~~-.1) // 0
console.log(~~.1) //0

坑三: 对于稀疏数组的输出差异

在谷歌浏览器中,对于长度为三,无内容的稀疏数组显示为undefined*3,对于长度为三,但内容都赋值为undefined的数组,显示为[undefined, undefined, undefined].但是此情况在IE浏览器中显示的内容都是两个等号!不过在火狐中相对比较正常,输出的是文字”三个空的数组”和[undefined, undefined, undefined]

坑四: JSON.stringify的妙用:

在序列化为JSON对象时,将该对象选择性输出,以得到想要的值;

1
2
3
4
5
6
var a = {
b: 42,
c: '41',
d: [1,2,3]
}
console.log(JSON.stringify(a, ['b','d'])) //{"b":42,"d":[1,2,3]}

当然,这个时候stringify还可以传递一个函数进去进行判断.

1
2
3
4
5
6
7
8
var a = {
b: 42,
c: '41',
d: [1,2,3]
}
console.log(JSON.stringify(a, function(k, v){
if(k !== 'c') return v;
})) //{"b":42,"d":[1,2,3]}

JSON.stringify()还有一个参数space,用来指定输出的缩进格式,space为数值时表示缩进的字符数,还可以是字符串,为字符串时最前面的十个字符用于每一级的缩进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a = {
b: 42,
c: '41',
d: [1,2,3]
}
console.log(JSON.stringify(a, null, "------------------"));
//{
//----------"b": 42,
//----------"c": "41",
//----------"d": [
//--------------------1,
//--------------------2,
//--------------------3
//----------]
//}

从上面来看,使用位运算得到的值和Math.floor() 的值不尽相同,使用位运算相当于直接去掉了数字的小数点.

坑五: 当在函数内部为变量指定新值后,并不影响传参的值.

当函数内部制定了变量值后,输出的值是不一样的,我们来看一下例子:

1
2
3
4
5
6
7
8
9
10
function foo(x) {
x.push(4);
console.log(x); //输出的是[1,2,3,4],没毛病
x = [4,5,6];
x.push(7);
console.log(x); //输出[4,5,6,7]这个没毛病
}
var a = [1,2,3];
foo(a);
console.log(a); //这个情况下,a的值其实是[1,2,3,4];

其实主要的原因是这样的,当我们的a作为参数传到foo函数中的时候,foo中的参数x其实是获得了一个到a数组的指针,当x进行相应的数值处理操作的时候,会直接作用到a上面,但是当x的指针改变了,也就是x被重新赋值的时候,x的指针就指向新的[4,5,6]数组了,这个时候其实后面的push(7)的操作已经是对于新的数组,并没有对a数组进行相应的操作,故最后返回的a的值只是[1,2,3,4]

坑六: 为变量赋予常量值的问题

一个很小的问题(其实涉及到的知识点和上面是类似的),当我为一个变量赋予了一个常量值,但通过函数对这个常量值进行更改,那么更改会不会体现到这个常量值中呢?

1
2
3
4
5
6
7
function foo(x) {
x = x + 1;
console.log(x);
}
var a = 2;
foo(a);
console.log(a); //此时a还是为2

坑七: 关于浅复制的一些小技巧(也是对上面问题的另一种出理方案)

使用slice()方法对变量进行浅复制,达到不影响变量原来的值的目的.

1
foo(slice() )

坑八: new出的对象

使用new方法new出来的变量都是属于对象,因此进行类型检测时都会显示为object型.

坑九: 关于隐式类型转换

对new出来的对象来讲,对其进行判断会有一个自动的隐式类型转换过程,自动调用数组中的valueof()方法,因此就有了以下这样的奇葩现象:

1
2
3
4
5
6
7
8
var a = 2;
Number.prototype.valueOf = function() {
return a++;
}
var b = new Number(2);
if(b == 2 && b ==3) {
console.log('WTF?') //WTF?
}

其实这个问题很好解释,每次对b进行判断都是会调用其valueof方法,而valueof方法中a会自增1,因此会有b又等于2,又等于3的情况.

文章目录
  1. 1. 坑一: 关于parseInt()方法转换字符串的问题,神坑!
  2. 2. 坑二: 位运算符~的妙用:
  3. 3. 坑三: 对于稀疏数组的输出差异
  4. 4. 坑四: JSON.stringify的妙用:
  5. 5. 坑五: 当在函数内部为变量指定新值后,并不影响传参的值.
  6. 6. 坑六: 为变量赋予常量值的问题
  7. 7. 坑七: 关于浅复制的一些小技巧(也是对上面问题的另一种出理方案)
  8. 8. 坑八: new出的对象
  9. 9. 坑九: 关于隐式类型转换
|