你不知道的JS(十):强制类型转换

  • 在对类型和值有全面的了解之后,讨论一个非常有争议的话题:强制类型转换

  • 关于强制类型转换是一个设计上的缺陷还是有用的特性,这一争论从JavaScript诞生就有了。

  • 在很多书籍中强制转换被说成危险。晦涩和糟糕的设计。

一、值类型转换

  • 将值从一种类型转换成另一种类型通常称为类型转换,这是显式的情况;隐式的情况称为强制类型转换。
  • 强制类型转换主要将值转换为相应的字符串、数字、布尔值,不会返回对象和函数。
  • 下面两种方式都是将数字转换成字符串
var a = 42;
var b = a + ""; // 隐式强制类型转换
var c = String(a); // 显式强制类型转换

关于显隐式是作者个人的区分:简而言之,显式类型转换比较明显。

二、抽象值的操作

1. ToString

  • 将引用类型数据转换为字符串,
  • 使用工具函数JSON.stringify()在讲JSON对象转为字符串时也使用了toString()

2. ToNumber

  • 将非数字值转化为数字来使用。
  • 比如:true转换为1,false转换为0

3. ToBoolean

  • 我们常常误以为数值1和0分别等同于true和false,但其实不是这样。(其它语言可能是)
  • 其实布尔值和数字是不一样的,虽然1可以强制转换为true。

假值

假值,可以转换为false的值。以下都是假值:

  • undefined
  • null
  • +0、-0和NaN
  • “”

假值对象

  • 所有对象都是真值。假值对象不属于JavaScript语言的范畴。
  • 浏览器在某些特定情况下,在常规JavaScript语法的基础上,自己创建了一些外来值,这些就是“假值对象”。

真值

真值就是假值之外的值,比如

var a = []; // 真值

三、显式强制类型转换

显示强制类型转换就是那些显而易见的类型转换。

  • 字符串与数字

    • String()Number()toString()
    • 加号(也可以认为是隐式)
  • 解析数字字符串

    • Number()parseInt()
    • 解析从左到右的顺序,如果遇到非数字字符就停止。
  • 转换为布尔值

    • Boolean()!!

四、隐式强制类型转换

  • 隐式强制类型转换,是指哪些隐蔽的强制类型转换,副作用不明显。
  • 显式类型转换旨在让代码更加清晰可读,隐式强制类型转换会让代码变得晦涩难懂。
  • 隐式强制类型转换的作用是减少冗余,让代码简洁。
  • 所以就是在代码简洁和可读性之间进行取舍

1. 字符串与数字之间

  • +运算符
    • 能用于数字计算,也能用于字符串拼接。
    • 只要有一个为字符串就会拼接,实际更加复杂一些。
    • 比如a+“”;这种将数字转换为字符串的方式非常常见。
  • -运算符
    • 强制转换为数字
    • 例如:a - 0 会将a强制转换为数字

2. 转换为布尔值

作为条件判断表达式的时候,会强制转换为布尔值。

  • if()语句
  • while()循环
  • a?b: c三元表达式
  • 逻辑运算符 ||&&左边的操作数

3. ||和&&

  • 与其他语言不同,在JavaScript中它们返回的不是布尔值。
  • 它们返回的值是两个操作数中的一个。
  • ||,如果第一个操作数为true,就返回第一个操作数的值,如果为false就返回第二个的值

&&则相反。

function foo() {
	console.log(a);
}
var a = 42;
a && foo();// 42

foo()只有在条件判断a通过时才会被调用。

五、宽松相等和严格相等

宽松相等是:==

严格相等是:===

1. 相等比较操作的性能

  • 常见误区==检查值是否相等,===检查值和类型是否相等。
  • 正确解释==允许在相等比较中进行强制类型转换,而===不允许。
  • 区别:第二种解释中 == 的工作量大一些,因为类型不同还要强制转换。(性能上也只是只有细微差别)
  • 理解
    • 如果比较的两个值类型相同,则两者使用相同的算法。
    • =====都会检查操作数的类型,区别在于操作数不同时它们的处理方式不同。

2. 抽象相等

ES5规范的11.9.3节的“抽象相等比较算法”定义了==运算符的行为。涵盖了它们进行强制类型转换的方式。
具体查看
JavaScript 中的相等性判断 - JavaScript | MDN (mozilla.org)

这里讨论一些比较常见的规则。

  • 如果两个值的类型相同,就仅比较它们是否相同。(42等于42)除了NaN不等于NaN,+0等于-0。
  • 如果比较的是两个对象,两个对象指向同一个值时,即视为相等,不发生类型转换。
  • 如果比较的是两个不同类型的值,会将其中之一或两者都转换为相同的类型后进行比较。

字符串与数字

  • 宽松比较是字符串强制转换为数字进行比较
var a = 42;
var b = "42";
a === b; // false
a == b; // true
  • b转换为数字是42,也就是两边42,相等。

其他类型与布尔值

  • 举个字符串和布尔值的情况。这里是两边都转换为数字,再进行比较。
var a = "42";
var b = true;
a == b; // false
  • “42”通过ToNumber()为42,true转换为1,所以不相等。
  • 建议不要使用 == true==flase,因为可能对布尔值进行转换,产生意想不到的结果。

null和undefined

null == undefined; // true
  • 这两个之间的强制转换是安全可靠的,可以利用
if(a === undefined || a === null) {
 // ...
}
// 相当于
if(a == null){
	// ...
}

对象与非对象

  • 对象会调用ToPrimitive进行抽象操作
var a = 42;
var b = [ 42 ];
a == b; // true
  • [ 42 ]先转换为“42”,再转换为42,对比二者相等。

比较少见的情况

假值的相等比较,存在24中情况,有些还无法理解,比如:

false == ""; // true
false == []; // true
false == {}; // false
...

极端情况

[] == ![] // true

这里是![]变成false[] == false结果为true

还有

2 == [2]; // true
"" == [null]; //true

3. 安全运用强制类型转换

  • 如果两边的值中有true或者false,千万不要使用==
  • 如果两边的值中有[]""或者0,尽量不要使用==
  • typeof操作是绝对安全的。(typeof == “function”typeof === "function"一样)
  • =====选择哪一个取决于是否允许再相等比较中发生强制类型转换。
  • 强制类型转换在很多地方非常有用,能够让相等比较更简洁,但是在部分情况下确实很危险

4. 抽象关系比较

  • a < b中存在强制转换,但是不太引人注意。
  • 比较双方调用ToPrimitive,如果结果出现非字符串,就转换为数字,进行数字比较。
  • 如果双方都是字符串,或者调用ToPrimitive结果为字符串,就进行字符串比较。(字符串比较按字母顺序)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值