,Javascript 是一种弱类型语言,这意味着变量是没有明确类型的,而是由 JavaScript 引擎在编译时隐式完成。类型转换就是将一种数据类型转换为另一种数据类型,例如:,Javascript 使用严格相等(===)和宽松相等(==)来测试两个值的相等性,类型转换仅在使用宽松相等运算符时发生。当使用 === 测试严格相等时,要比较的变量的类型和值都必须相同,例如:,在上面的代码中,10和10都是数字并且是完全相等的,所以正如预期的那样返回了true
,两个 NaN 永远不会相等。当使用 == 测试宽松相等时,可能会发生隐式转换:,对于任何数据类型,无论是原始类型还是对象,都可以进行类型转换。尽管原始类型和对象的转换逻辑各不相同,但是都只能转换为三种类型:字符串(string)、数字(number)、布尔值(boolean)。,JavaScript 中的类型转换有两种方式:,下面先来看看 JavaScript 中的显式和隐式类型转换。,我们可以通过 JavaScript 内置的一些 API 将一种类型转换为另一种类型,这称为显式类型转化。执行显式类型转换的最简单方法是使用 Boolean()、Number() 和 String()、parseInt()等函数,例如:,隐式类型转换是将一种数据类型转换为另一种数据类型(确保在相同数据类型之间完成操作)以使运算符或函数正常工作,这种转换是由 JavaScript 编译器自动完成的,隐式类型转换也称为类型强制。例如:,下面这些常见的操作会触发隐式地类型转换,编写代码时要格外注意:,下图是在使用 == 时,判断两个操作数是否相等的总结(绿色表示相等,白色表示不等):,,将数据类型转换为字符串称为字符串转换,可以使用 String() 函数将数据类型显式转换为字符串。当一个操作数是字符串时,可以通过使用 + 运算符来触发隐式字符串转换。,Number对象的 toString() 方法会返回指定 Number 对象的字符串表示形式。String()和 new String() 会把对象的值转换为字符串。,String() 和 toString() 方法会将布尔值转化为对应的字符串形式。,String() 方法会将数组元素通过逗号连接起来,无论嵌套多少层,都会将其展开并返回元素拼接好的字符串。如果是空数字,会返回空字符串:,使用 String() 方法会将对象转化为 ‘[object Object]’,无论对象是否为空对象:,使用 String() 方法会将 null、undefined、NaN 转化为其对应的字符串形式:,当任何数据类型使用+
运算符与字符串连接时会发生到字符串的转换(隐式转换):,所以,当我们想要创建一个操作并且操作数类型之一是字符串时,应该小心使用类型强制转换。,下面是 ECMAScript 规范中将数据类型转换为字符串的规则:,,ECMAScript 规范:https://262.ecma-international.org/5.1/#sec-9.8,将数据类型转换为布尔值称为布尔转换。这种转换既可以由 Boolean() 函数显式完成,也可以在逻辑上下文中隐式完成(如if/else )或通过使用逻辑运算符( ||、&&、! )触发。,使用 Boolean() 方法转化字符串时,只有当字符串为空时会返回false,其他情况都会返回 true:,使用 Boolean() 方法转化数字时,只有 0、-0 或 NaN 会转化为 false,其他情况会返回 true:,使用 Boolean() 方法转化数组或对象时,无论数组和对象是否有内容,都会返回true:,使用 Boolean() 方法转化null或undefined时,都始终返回 false:,在数学运算中,true 转换为 1,false 转换为 0:,注意,逻辑运算符,例如 || 或 && 内部进行布尔转换,但实际上返回原始操作数的值,即使它们不是布尔值。,可以使用双感叹号(!!)来将变量转为为布尔值:,if、else if、while、do/while 和 for 使用与 &&、||、! 相同的隐式类型转换方式(逻辑表达式)。,下面是在 if 语句(逻辑上下文)中的隐式转换规则(绿色为true,白色为false):,,除了下面这些之外的所有其他值都是真值,包括对象、数组、日期等。甚至所有Symbol、空对象和数组都是真值。,可以通过以下方式来过滤数组中的假值:,我们可以会遇到一种情况,当使用 5 == true 时,结果为false,而使用if(5) {}时,则 5 被认为是 true 并进入if/else语句:,这种情况下,即一个值和数字进行比较时,JavaScript 会试图将这个值转换为数字。所以,当比较5 == true 时,JavaScript 倾向于将true转换为1,因为 1不等于5,因此结果为 false。而在if(5) {}的情况下,5 被转换为布尔值,而 5 是一个真值,所以它进入if块。在这种情况下,可以选择显式转换以避免错误,因为 5 是一个真值,可以执行Boolean(5) == true,这样就会返回true了。,下面是 ECMAScript 规范中将数据类型转换为布尔值的规则:,,ECMAScript 规范:https://262.ecma-international.org/5.1/#sec-9.2,将数据类型转换为数字称为数字转换,可以使用Number()、parseInt()、parseFloat()等方法将数据类型显式转换为数字。当一个值不能被强制转换为一个数字时,就会返回 NaN。,当把字符串转换为数字时,JavaScript 引擎首先会修剪前导和后置空格、\n、\t 字符,如果修剪后的字符串不代表有效数字,则返回 NaN。 如果字符串为空,则返回 0。,可以看到,parseInt 函数会从字符串中读取一个数字并删除它后面所有字符,但是如果数字前面有字符(空格除外),那么它将输出 NaN。,当使用 Number() 将布尔值转化为数字时,true 会转化为 1,false 会转化为 0。,当使用 Number() 将 null 转化为数字时,会返回 0:,当使用 Number() 将 undefined、数组、对象、NaN 转化为数字时,会返回 NaN:,可以使用map遍历数组元素,并使用需要的类型来进行类型转换:,在表达式中,当我们将 == 运算符应用于 null 或 undefined 时,不会发生数字转换。 此外,null 只等于 null 或 undefined,不能等于其他任何值:,根据运算符优先级,+ 运算符具有从左到右的关联性,因此如果有一个表达式 2 + 3 + ‘4’ + ‘number’ ,则操作按以下方式完成:,NaN 不等于任何其他类型,甚至它本身:,上面的例子中,可以清楚地看到一些意想不到的结果:将 null 转换为数字时返回了 0,而将 undefined 转换为数字返回了 NaN。两个操作都应该返回 NaN,因为这两种值类型显然都不是有效的数字,将空字符串转换为数字时也返回了 0。,下面是 ECMAScript 规范中将数据类型转换为字符串的规则,清楚的解释了上面的异常现象:,,另外,在 ECMAScript 规范中,还提到一点:,,意思就是:为空或仅包含空格的 StringNumericLiteral 将转换为 +0。这也就解释了为什么将空字符串转换为数字时也返回了 0。,ECMAScript 规范:https://262.ecma-international.org/5.1/#sec-9.3。,Symbol 只能进行显式转换,不能进行隐式转换。也就是说,Symbol不能被强制转换为字符串或数字,这样它们就不会被意外地用作本来应该表现为 Symbol 的属性。,当使用 console.log() 来打印 symbol 时,它之所以有效,是因为 console.log() 在 symbol 上调用了 String() 方法以创建可用的结果。,如果尝试直接使用字符串连接 symbol,它将抛出TypeError:,将 mySymbol 连接到字符串需要首先将 mySymbol 转换为字符串,并且在检测到强制转换时会抛出错误,从而阻止以这种方式使用它。,同样,我们不能将 symbol 强制转换为数字,所有数学运算符在与符号一起使用时都会引发错误:,介绍完了基本数组类型的转化,下面来看看对象类型的转化。例如,当执行 obj_1 + obj_2 或者 obj_1 – obj_2时,都会先将对象转换为原始类型,然后将其转换为最终类型。当然,这里的转化仍然只有三种类型:数字、字符串和布尔值。,对象通过内部的 ToPrimitive 方法将其转换为原始类型,该算法允许我们根据使用对象的上下文来选择应如何转换对象。从概念上讲,ToPrimitive 算法可以分为两部分:Hints 和 Object-to-primitive 转换方法。,,Hints 是 ToPrimitive 算法用于确定对象在特定上下文中应转换为什么的信号。有三种情况:,所有内置对象(日期除外)都将default认为是number,Date 日期对象将default认为是string。,在 ToPrimitive 算法根据 Hints 确定对象应转换为的原始值类型之后。 然后使用 Object-to-primitive 转换方法将对象转换为原始值。有三种情况:,在上面的代码中,Person 变成了一个对象字符串或数字,具体取决于转换上下文。 toString() 方法用于 Hints = “string” 的转换,valueOf() 用于其他情况(Hints 为“number”或“default”)。,你可能希望在一个地方处理所有转换。 在这种情况下,只能像这样实现 toString() 方法:,Symbol.toPrimitive:与 toString() 和 valueOf() 方法不同,Symbol.toPrimitive 允许覆盖 JavaScript 中的默认对象到原始值的转换(其中 toString() 和 valueOf 方法由 ToPrimitive 算法使用)并定义我们希望如何将对象转换为原始类型的值。 为此,需要使用此 Symbol 名称定义一个方法,如下所示:,例如,这里的 Person 对象使用 Symbol.toPrimitive 执行与上面相同的操作:,可以看到,单个方法 Person[Symbol.toPrimitive] 处理了所有转换情况。需要注意,在没有 Symbol.toPrimitive 和 valueOf() 的情况下,toString() 将处理所有原始类型转换。,下面是将对象转化为布尔值、字符串、数字时的执行过程:,Javascript 中的所有对象都转换为 true,包括包装对象 new Boolean(false) 和空数组。 对象到布尔值的转换不需要对象到原始类型算法。,当需要将对象转换为字符串时,Javascript 首先使用 ToPrimitive 算法(Hints = “string”)将其转换为原始类型,然后将派生的原始类型转换为字符串。例如,如果将对象传递给 String() 这样的内置函数,或者在模板字符串中插入对象时。,当需要将对象转换为数字时,Javascript 首先使用 ToPrimitive 算法(Hints = “number”)将其转换为原始类型,然后将派生的原始类型转换为数字。 期望数字参数的内置 Javascript 函数和方法以这种方式将对象参数转换为数字,例如 Math()。,当某些 Javascript 运算符的操作数是对象时,也会发生类型转换:
© 版权声明
文章版权归作者所有,未经允许请勿转载。