类型 & 值
内置类型
JavaScript 一共有 7 中内置类型:null
, undefined
, boolean
, number
, string
, object
和 Symbol
使用 typeof
可以检查它们的类型;但是 typeof null
返回 'object'
(这是一个 bug)
因此,如果要想检测一个值为 null
需要使用:
强制类型转换
我们在讨论强制类型转换时,转换的结果都是基本类型。
我们可以把强制类型转换分为隐式和显式两种,例如下面:
当然,隐式和显式只是相对的;并没有绝对的划分
抽象值操作
ToString
null
返回'null'
,undefined
返回'undefined'
,true
返回'true'
数字返回对应的字符串,极小或极大的使用指数形式
普通对象,除非自定义;否则返回内部
[[Class]]
属性的值数组的
toString()
方法被重定义了,它将所有元素以 “ , ” 分割再拼成字符串
toString()
可以被显式调用,也可以在需要字符串化时自动调用。
JSON.stringify()
我们还可以对对象使用 JSON.stringify()
来将它序列化为字符串。
在这个过程中,也是用到了 ToString
的上述规则。不过他们还是不一样的!
值得一提的是,在 JSON.stringify()
的过程中,会忽略一些 “不安全的 JSON 值” ,即:undefined
, function
, symbol
以及循环引用(对象之间互相引用)。
这些 “不安全的 JSON 值” 在序列化时,会被自动忽略;如果他们存在某一个数组中,那么则会在对应位置返回 null
可以通过定义 toJSON()
方法来返回一个安全的 JSON 值
注意,这里介绍 JSON.stringify()
并不是因为它也是一个强制类型转换。而是在它其中,也运用到了 ToString
的一些规则。
例如当遇到对象中某一个属性是 null
,它就会应用规则将其转换为 'null'
ToNumber
true
转换为 1,false
转换为 0undefined
转换为NaN
null
转换为 0字符串先尝试转换,若失败则变为
NaN
对象先转换为相应的基本类型;若非数字,再应用上面的规则。将对象转换为基本类型会使用
ToPrimitive
操作,具体的过程为:检查是否有
valueOf
方法;若有,返回基本类型值如果没有则使用
toString()
的返回值,再执行上述规则如果
valueOf
和toString()
均不会返回基本类型,则产生TypeError
ToBoolean
在 JavaScript 当中,数字 1, 0 不等同于 true
和 false
。我们虽然可以使用强制类型转换将 1 变为 true
,(反之亦然)。但是他们不能画等号!
转换为 boolean
时只需要检查这个值是否为 “假值” ,以下都是假值
undefined
null
false
''
+0, -0,
NaN
以上 “假值” 将会转换为 false
;除此之外,所有值都转换为 true
对象,数组都是真值,即便是对假值进行封装:
显式强制类型转换
字符串和数字之间转换
使用内置的 String()
和 Number()
函数可以实现字符串和数字之间的相互转换。
注意不需要使用 new
构造调用它们,因此并不创建封装对象。
String()
和 Number()
分别遵循上面介绍的 ToString
和 ToNumber
抽象值操作的规则。
此外,还可以通过以下的方法来进行 “显式转换”
除了 Number
可以将字符串转换为数字,还可以使用 parseInt()
方法;但他们之间有点区别:
Number
不支持解析字符串中的一部分,而 parseInt()
在遇到非数字字符时可以截止,如果失败再返回 NaN
parseInt
只支持传入字符串,他不能解析其他类型的值。它会先将传入的值转换为字符串,再继续下去。
当然还有
parseFloat
将值转换为浮点数
转换为 boolean
可以使用 Boolean()
内置函数来显式地将值转换为 boolean;不过一种更常用的方式是使用 !!
隐式强制类型转换
字符串和数字之间的转换
在使用 +
运算的时候,会发生隐式转换;因为 +
既可以执行加法运算,也能进行字符串拼接。他的具体规则如下:
如果其中的一个操作符是字符串,或者可以通过
ToPrimitive
抽象操作转换为字符串;那么就执行拼接否则,执行数字加法运算
ToPrimitive
操作的具体过程如下:
先调用其
valueOf()
获得基本类型值如果没有,再调用
toString()
方法
这个操作和
ToNumber
类似
利用上述特性,我们通常会使用 0 + ''
这种操作来将数字转换为字符串。
此外,还可以使用 a - 0
, a * 1
, a / 1
来隐式转换为数字。
boolean 转换为数字
true
会转换为 1,false
会转换为 0
转换为 boolean
在以下几种情况下,都会发生隐式的转换,将值转换为 boolean:
if 语句
for 语句的第二个表达式
while, do ... while 语句
? : 三目运算符
|| && 左边的操作数
||
&&
操作符的实际行为可能和你想象中的不太一样,因为他们的返回值并不一定是 boolean
相反,他们会返回左右两个操作数中的某一个;具体操作如下:
首先对左边的操作数进行判断,此时可能会发生隐式转换将值变为 boolean
对于
||
如果判断为true
则返回左边的操作数;否则返回右边对于
&&
如果判断为true
则返回右边的操作数;否则返回左边
== 和 ===
两者的区别在于:==
允许在比较时进行强制类型转换,而 ===
不允许。
也就是说,如果两个值的类型相同;那么他们使用 ==
或者 ===
效果是相同的。
== 规则
如果两个值的类型相同,则直接比较他们是否相等;不过以下两种情况注意:
NaN
不等于NaN
+0 等于 -0
如果是两个对象,那么之比较他们的引用是否相同。
但是,如果两个值的类型不同;那么就会发生隐式强制类型转换,将其中一个或者两个转换为相同类型再进行比较。下面将分别介绍不同的情况:
字符串和数字比较
将两者之间的字符串转换为数字,然后再执行比较。
转换使用
ToNumber
抽象操作
其他类型和 boolean 比较
不要和 Boolean()
强制转换时判断假值混淆,以下结果可能出乎你的预料:
正确的过程是:会将其中的 boolean 值转换为 Number,然后再比较
因此,下述表达式就能返回 true
这里有一个坑就是你很容易以为这里会对 ”非 boolean“ 的那个值做一次隐式转换将其变为 boolean。但事实完全相反,我们会将那个 boolean 值转换为 1 或者 0;然后在执行比较!
但是你可以通过 !!
进行显式转换:
null 和 undefined 比较
在 ==
时,null
和 undefined
是相等的
注意,只有 null
和 undefined
之间的 ==
是返回 true
的,但是如果他们和其他 “假值" 进行比较,都不会返回 true
:
对象和非对象之间比较
如果将一个对象(对象、数组、函数)和一个基本类型(string、number、boolean)进行比较,规则如下:
使用 ToPrimitive
抽象操作将对象转换为基本类型,再执行比较。
需要注意的是,如果非对象是一个 boolean;则会想将其转换为数字。
抽象关系比较
在执行 a < b
判断的时候,如果两边类型不同;也会发生隐式转换
如果双方都是字符串,则按照字母顺序来比较
不然的话,双方都先调用
ToPrimitive
,如果出现非字符串,则再统一执行ToNumber
转换为数字后再比较
不过有些情况就比较特别了,注意仔细甄别:
然而,更让你意外的是:
这是因为,JavaScript 中 <=
操作其实是 !(a > b)
,因此上面的结果返回 true
另外需要指出:与 ===
不同的是,关系比较没有 ”严格比较“。因此当两边类型不同时,会发生隐式转换。请尽量保证两边比较的类型时相同的!
Last updated