一、隐式类型转换
1. 原始值和原始值之间的转换
(1)布尔值环境
(2)字符串环境
(3)数字环境
2. 原始值和对象之间的转换
(1)原始值转换为对象
(2)对象转换为原始值
3. 运算符引起的隐式类型转换
二、显式类型转换
一、隐式类型转换
JavaScript 是一种无类型(notype)语言——松散类型、动态类型的语言。因此,在 JavaScript 中定义一个变量时,不需要指定变量的数据类型(赋的值是什么类型变量就是什么类型),这就使得 JavaScript 可以很方便灵活地进行隐式类型转换。
所谓隐式类型转换,就是不需要程序员定义,JavaScript 会自动将某一个类型的数据转换成另一个类型的数据。JavaScript 隐式类型转换的一般规则是:将类型转换到环境中应该使用的类型。
1. 原始值和原始值之间的转换
(1)布尔值环境
当 JavaScript 期望使用一个布尔值时,JavaScript 就会自动将其他类型的数据转换成布尔类型,如 if 和 while 语句中的逻辑条件表达式
。在布尔值环境中,
① 对于 number 数字型,在遵从非零即true的原则基础上,NaN (特殊的数值)也会转换为false,即除了 0 和 NaN 会隐式转换为 false 之外,其他所有 number 类型(包括 Infinity 和 -Infinity)都会转换成 true;
② 对于 string 字符串型,遵从 非空即true 的原则;
③ 对于 null 和 undefined,会转换为 false。
if(!0){console.log("!0");} //!0
if(1){console.log("1");} //1
if(-1){console.log("-1");} //-1
if(Infinity){console.log("Infinity");} //Infinity
if(-Infinity){console.log("-Infinity");} //-Infinity
if(!NaN){console.log("!NaN");} //!NaN
if(!null){console.log("!null");} //!null
if(!undefined){console.log("!undefined");} //!undefined
(2)字符串环境
当 JavaScript 期望使用一个字符串时,JavaScript 就会将其他类型的数据转换成字符串类型,如任何类型的数据与字符串类型的数据作 "+" 运算
(此时的相加操作不再是是数学意义上的的加法,而是表示拼接的意思)。
console.log(1 + "1"); /* 11 */
console.log(true + "1"); /* true1 */
console.log(undefined + "1"); /* undefined1 */
console.log(null + "1"); /* null1 */
console.log(Infinity + "1"); /* Infinity1 */
console.log(NaN + "1"); /* NaN1 */
(3)数字环境
当 JavaScript 期望使用一个数字时,JavaScript 就会将其他类型的数据转换成数字类型(如果转换结果无意义的话则返回 NaN)。如,字符串如果不是纯数字,转换成数字时会转换成 NaN(允许在开始和结尾处带有空格)。NaN 除了和字符串做 "+" 运算,与其他数据做算术运算的结果始终都是 NaN(包括 NaN 本身)。
一个典型的数字环境是:任何其他数据类型(Indefinite 和 NaN 是特殊数值)除了和字符串做 "+" 操作外,与数字类型做算术运算的时候,其他数据类型都会自动转换成数字。
console.log(true + 1); /* 2 */
console.log(false + 1); /* 1 */
console.log("2" * 3); /* 6 */
console.log(" 2" * 3); /* 6 */
console.log(" 2 " * 3); /* 6 */
console.log(" 2a " * 3); /* NaN */
console.log(null + 1); /* 1 */
console.log(undefined + 1); /* NaN */
console.log(NaN + 1); /* NaN */
console.log(Infinity + 1); /* Infinity */
console.log(-Infinity + 1); /* -Infinity */
2. 原始值和对象之间的转换
(1)原始值转换为对象
原始值通过调用 String()、Number() 或 Boolean() 构造函数,转换为它们各自的包装对象(见上一篇文章 数据类型 之 "拥有方法的类型和不能拥有方法的类型")。当然,null 和 undefined 除外,因为 null 和 undefined 没有包装对象,当将它们用在期望是一个对象的地方都会造成一个类型错误(TypeError)异常,而不会执行正常的转换。
(2)对象转换为原始值
①字符串环境
所有的对象(包括数组和函数)都转换为 true。对于包装对象亦是如此:new Boolean(false) 是一个对象而不是原始值,它将转换为 true。
②字符串环境
通过调用待转换对象的一个方法来完成。然而,事实上 JavaScript 对象有两个不同的方法来执行转换——toString() 和 valueOf()。
JavaScript 中对象转换为字符串经过了如下步骤:
- 如果对象具有 toString() 方法,则调用这个方法。如果它返回一个原始值,JavaScript 将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。原始值到字符串的转换如上文所述。
- 如果对象没有 toString() 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf() 方法。如果对象存在 valueOf() 方法,执行 toString() 方法相同的操作。
- 如果 JavaScript 无法从 toString() 或 valueOf() 获得一个原始值,这是它将抛出一个类型错误(TypeError)异常。
③数字环境
和对象转换为字符串执行的操作相同,只是 JavaScript 会首先尝试使用 valueOf() 方法。
注意
对于数组来说,它继承了默认的 valueOf() 方法,这个方法返回一个对象而不是一个原始值,因此,数组到数字的转换是调用 toString() 方法——空数组转换为空字符串,空字符串转换为数字 0 ;含有一个元素的数组转换为字符串的结果和这个元素转换为字符串的结果一样;而如果数组只包含一个数字元素,这个数转换为字符串,再转换会数字。
特殊情况:对象到原始值的转换,日期对象会首先尝试调用 valueOf() ,然后调用 toString() 。不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串。
*附上《JavaScript 权威指南》(第6版)表3-2:JavaScript 类型转换
![《JavaScript 权威指南》(第6版)表3-2:JavaScript 类型转换](https://i-blog.csdnimg.cn/blog_migrate/d9743dad0be7cc3a4be1b6b485494db4.png)
3. 运算符引起的隐式类型转换
JavaScript 有两种比较方式:严格比较运算符和转换类型比较运算符。
(1)对于严格相等(===)来说,首先计算其操作数的值,然后比较这两个值,比较过程没有任何类型转化。严格相等的比较原理如下:
- 如果两个值类型不相同,则返回 false。
- 如果两个值都是 null 或者都是 undefined ,则返回 true。
- null 和 undefined,返回 false。
- NaN 不会与任何值等同,包括它自己。
- 0 和 -0 返回 true。
- 如果两个值为字符串,且所含的对应位上的 16 位数完全相等,则它们相等。两个字符串可能含义完全一样且所显示出的字符也一样,但具有不同编码的 16 位值。JavaScript 并不对 Unicode 进行标准化的转换,因此像这样的字符串通过 "===" 和 "==" 运算符的比较结果也不相等。String.localCompare() 提供了另外一种比较字符串的方法。
- 如果两个引用值指向同一个对象、数组或函数,则它们是相等的。如果指向不同的对象,则它们是不等的,尽管两个对象具有完全一样的属性。
(2)对于相等运算符(==)来说,会在进行比较之前,将两个操作数转换成相同的类型,然后进行严格比较。相等运算符的比较原理如下:
- 两个操作数的类型相同,则和上文所述的严格相等的比较规则一样。
- 字符串和数字,把字符串转换成数字。
- 布尔值和数字,把布尔值转换成数字。
- 对象和数字或字符串,使用 valueOf() 或 ttoString() 方法将对象转换为原始值(一个字符串或数字类型的值)之后,再进行比较。如果尝试转换失败,则产生一个类型错误异常。
- 对象和对象,比较其内部引用,当且仅当它们的引用指向内存中的相同对象(区域)时才相等,即它们在栈内存中的引用地址相同。
- null 和 undefined,返回 true。
(3)对于关系运算符(<、>、<=、>=)来说,会先将操作数转换为原始值,使它们类型相同,再进行比较。其比较原理如下:
- 如果操作数是对象,对象转换为原始值再来比较。
- 在对象转换为原始值之后(或者不是由对象转换而来的原始值),如果两个操作数都是字符串,那么按照字母表的顺序对两个字符串进行比较。如果至少有一个操作数不是字符串,那么两个操作数都将转换为数字进行数值比较。
- 如果其治好啊有一个操作数是 NaN,则返回 false。 (未完待续)
二、显式类型转换
1. 显示类型转换最简单的方法就是使用 Boolean()、Number()、String() 或 Object() 函数。当不通过 new 运算符调用这些函数时,它们会作为类型转换函数并按照上文表3-2所描述的规则做类型转换。
2. 除了 null 和 undefined 之外的任何值都具有 toString()方法,这个方法的执行结果通常和 String() 方法的返回结果一致。
3. 在计算机程序中,数字的解析和格式化是非常普通的工作,JavaScript 中提供了专门的函数和方法来做更加精确的数字到字符串和字符串到数字的转换。
(1)Number 类定义的 toString() 方法,返回一个相应的字符串。如果调用该方法的对象不是 Number 时,抛出 TypeError 异常。
(2)toFixed() 方法根据小数点后的指定位数将数字转换为字符串,从不使用指数计数法。
(3)toExponential() 方法使用指数计数法将数字转换为指数形式的字符串,其中小数点前只有一位,小数点后的位数则由参数指定。
(4)toPrecision() 方法根据指定的有效数字位数将数字转换成字符串。如果有效数字的位数少于数字整数部分的位数,则转换成指数形式。
(5)parseInt() 函数和 parseFloat() 函数 是全局函数,不从属于任何类的方法,它们更加灵活。parseInt() 只解析整数,而parseFloat() 则可以解析整数和浮点数。parseInt() 可以接收第二个可选参数,这个参数指定数字转换的基数,合法的取值范围是 2~36。