js的类型转化三两事儿

14次阅读

共计 2731 个字符,预计需要花费 7 分钟才能阅读完成。

在 js 中,类型转换是一个被非常多人诟病的地方。新手看了会发矇,老手看了会头疼。

类型转换,又成为 强制类型转换 ,主要区分为 显式强制类型转换 隐式强制类型转换

按我理解,类型转换的意思就很明显,就是当程序运行时需要此刻的变量的类型与变量的实际类型不符时,就会进行强制转换,在一些静态语言中,这个过程发生在编译阶段,或者干脆就抛出错误。而在 js 中,这个转换过程发生在运行时,所以你写代码的时候并不会意识到自己已经掉进坑里了。

显式强制类型转换 ,简单的说,就是你觉得你可以明面上一眼看出来的,比如‘’+ number,+string,Boolean(value); 而 隐式强制类型转换 就是反过来的意思。

举个栗子:

var a = 'value';
if (a == true) {console.log('a is true');
} else if (a == false) {console.log('a is false');
}

按照正常的脑回路,一般人不会这么写。但是确实是有人会写 if (a == true) {...} 这种语句,当然,后面的 else if (a == false) 是为了节目效果加的。即便是这样,a == true这种写法也是不可取的。

最后的输出是,两个都不输出。即在这个隐式强制类型转换中,a 即不会等于 true, 也不会等于 false。

首先解释一下为什么 a 既不等于 true, 也不等于 false。按照正常人类的脑回路,应该是将 a 先转换为布尔值,然后再将两个布尔值对比。这种情况下,a 转成布尔值只能转换成 true 或者 false。要是这么想,那你就是 too young, too simple 了

当使用 相等操作符 == 进行判断时,将遵循以下规则(来自红宝书):

· 如果又一个操作数是布尔值,则在比较相等性之前先将其转换为数值(false 转换为 0,而 true 转换为 1
· 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值
· 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf() 方法,用得到的基本类型值按照之前的规则进行比较
· null 和 undefined 是相等的
· 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值
· 如果一个操作数是 NaN, 则相等操作符返回 false。
· 如果两个操作数都是对象,则比较它们是不是同一个对象,是则返回 true, 否则返回 false

所以就可以知道上例中,转换是如何进行的。首先两个相等操作的操作数中都包含布尔值,先将布尔值转换为数值所以这里 true 转换为 1,false 转换为 0。接下来再次进行比较,此时两对操作数中都包含一个字符串操作数,则将字符串转换为数值, a 转换为数值是 NaN,此时再次进行比较,由于有一个操作数是 NaN,按照规则,返回 false。所以 a 既不等于 true 也不等于 false。

由上可以看出,使用 == 进行条件判断的时候是非常具有危险性的,尤其是当其中一个操作数为 true 的时候,如果另一个操作数不为布尔值,则很有可能就掉进坑里了。

那么一般在判断的时候怎么去进行判断比较好呢。我认为尽量不使用 == 操作符。使用 === 进行全等判断,或者直接将你需要判断的值丢进 if 判断里,比如 if (a == true) 可以改成 if (a) 或者 if (!!a) 这样就能避开 == 操作符的坑了。如果一定要使用 == 进行比较,不用不舒服,则最好先将操作数进行显式类型转换为同一类型的数据,再进行比较,

知其然就要知其所以然。
为什么 if (a)if (!!a)就可以避开 == 操作符的坑呢?它们进行强制类型转换时的转换规则又是怎样的。

其实在 if 的判断语句块内,如果判断值不是布尔值的话,会自动调用 Boolean()函数进行布尔值的转换。而!! 则相当于一次 Boolean()的值类型转换了。所以在 if 的判断语句里直接放入判断条件和显式的将判断条件进行转换,其作用是一样的。区别也只是在于是否对后续看代码的人友好了,如果后面代码维护可能是接触代码不深的新手,则建议进行显式的转换。

由上面的解释可以知道 if (a)if (!!a)if (Boolean(a))的作用是一样的,所以这里只要了解一下 Boolean()函数的转换规则就可以了:

任何非空字符串为 true,空字符串 (”) 为 false
任何非零数字值 (包括无穷大) 为 true,0 和 NaN 为 false
任何对象为 true,null 为 false
undefined 为 false

以上规则来自红宝书,部分内容省略

看以上的 Boolean()函数的转换规则,与我们日常工作中所需要的类型转换是非常契合的。
比如我们普遍会认为并要求 if 可以拦截空字符串,false,null,undefined,0 与 NaN

需要注意的是,虽然红宝书上并没明确指出,但 三元运算符 ( ? : ) 使用的转换规则也是 Boolean()函数的转换规则.

而除了条件判断,在其他一些操作里也会出现类型转换,比如 关系操作符(<, >, <=, >=):

var a = '23';
var b = '3';
console.log(a < b); // true

上面这个转换可能很多的前端开发工程师都掉进过坑里并摸不着头脑。
可能你也看出来了出现 ‘23’ 小于 ‘3’ 的原因或许是在于它们都是字符串。如果关系操作符 (<,>,<=,>=) 两边都是字符串,则比较两个字符串对应的字符编码。’2’ 的字符编码是 50,而 3 的字符编码是 51,所以这里出现了‘23’小于‘3’的情况。

到这里很多人都会惊叹一声,并表示记住了此知识点。但是这样往往是不够的,你需要深挖下去,需要确切的了解关系操作符的转换规则,才能确保不会再次掉进它的坑里。

如果两个操作数都是数值,则执行数值比较 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值
如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较
如果一个操作数是对象,则调用这个对象的 valueOf()方法,并用得到的结果根据前面的规则进行比较
如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较
如果一个操作数是 NaN,undefined,则返回 false
如果操作数为 null, ”, 则转换为 0 进行比较

多看看红宝书就会发现 js 中的类型转换其实坑还是很多的,还有一些加减乘除的操作符本身也会产生类型转换的问题。但是基本问题不是太大,所以就不单独拎出来了。

最后,一道思考题:

// do something ...
console.log(typeof a); // 'object'
console.log(a == false); // true

上面的对象为什么会等于 false,这个题是之前刷到的一道面试题,可不是我瞎编的。。

最后,欢迎斧正,没有仔细的准备,所以写的少且杂,也是作为自己的一个总结回顾吧。

正文完
 0