【译】JavaScript 怪异 1:值的隐式转换

这篇文章是 JavaScript 怪异系列的一部分

JavaScript 是对值的接受是很是宽松的。例如在任何期待一个 number 类型的值的地方,它不会拒绝来自其余类型的值,而是会试图转换它们:html

> '5' - '2'
3
> '5' * '2'
10
复制代码

自动转换成 boolean 值是不多出问题而且颇有用。这里先埋下个伏笔(咱们将用它解决一些怪异问题)。然而,自动转换为 string 可能会形成一些问题git

1. 隐式转换为 boolean 值:“truthy” 仍是 “falsy”

无论什么时候 JavaScript 接受一个 boolean 值时(例如,if 语句的条件),任何值均可以用。它要么解释为 true,要么解释为 false。下面的值都会被解释为 false:github

undefined, null
Boolean: false
Number: -0, +0, NaN
String: ''
复制代码

其余全部的值都会被看成 true。值被解释为 false 的称做 falsy(假值),值被解释为 true 的称做 truthy(真值)。你可使用 Boolean 函数来测试一个值会被解释为何。它会把它的参数转换为 boolean 值:web

> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true
复制代码

2. string 的隐式转换

在 web 开发中,你会常常获取到其实是 number 或 boolean 而看成 string 类型的值。例如,当用户在表单输入一些数据时。若是你忘记了显式转换这些 string 的话,JavaScript 会给你带来两个消极方面的惊喜:首先,不会有任何警告。其次,值会被自动转换,可是是错的。例如,操做符加号(+)就有问题,由于只要操做符的一边是 string 类型的,它就会当成字符串链接符。在下面的例子中,假设咱们执行的是 1 和 5 相加,而实际上,咱们执行的是 ‘1’ 和 ‘5’ 字符串链接app

> var x = '5';  // 错误假设:x 是 number 类型
> x + 1
'51'
复制代码

此外,还有一些极少数的 falsy 值,若是被转换为 string 类型的,就会被当成 truthy,例如:false函数

> Boolean(false)  // truthy?
false
> String(false)
'false'
> Boolean('false')  // truthy?
true
复制代码

例如:undefined测试

> Boolean(undefined)  // truthy?
false
> String(undefined)
'undefined'
> Boolean('undefined')  // truthy?
true
复制代码

3. object 的隐式转换

若是 JavaScript 期待的是 number 或 string 类型的值的时候,object 才会发生隐式转换。第一种状况下(期待 number),会按照三个步骤进行转换:ui

  1. 调用 valueOf() 方法,若是结果是原始类型(非 object),那么继续调用 ToNumber
  2. 不然,调用 toString() 方法。若是结果是原始类型,那么继续那么继续调用 ToNumber
  3. 不然,抛出一个 TypeError 错误

译者改:spa

  1. 调用 ToPrimitive, 若是是原始类型,直接返回
  2. 调用 valueOf() 方法,若是结果是原始类型,那么继续调用 ToNumber
  3. 不然,调用 toString() 方法。若是结果是原始类型,那么继续调用 ToNumber
  4. 不然,抛出一个 TypeError 错误

译者注:这里注意 Date 对象(object)特殊,valueOf 和 toString 调用顺序不一样翻译

note

第 1 步的例子:

> 3 * { valueOf: function () { return 5 } }
15
复制代码

第 3 步的例子:

> function returnObject() { return {} }
> 3 * { valueOf: returnObject, toString: returnObject }
TypeError: 没法将 object 转换为原始类型
复制代码

若是是 JavaScript 转换为 string 类型,那步骤 1 和步骤 2 进行交换:首先试图调用 toString() 方法,而后调用 valueOf() 方法

4. 最佳实践:显式转换

最好的办法是在使用它们以前就显式转换为指望的类型。一个迷你的解决方案是用 Boolean(),Number() 和 String() 方法:

function handleFormData(formData) {
    var givenName = String(formData.givenName);
    var age = Number(formData.age);
    ...
}
复制代码

这些函数总会返回一个值(它们永远都不会抛出异常)。然而 Number() 函数在它不能转换一个值时会返回 NaN [1]:

> Number('xyz')
NaN
> Number(undefined)
NaN
> Number(null)
0
> Number(true)
1
复制代码

更详细的解决方案是在你转换这些值时,先检查下它们的格式(例如,人们不能把 ‘xyz’ 做为它们的年龄),若是不对,要采起适当的解决措施

5. 引用

  1. NaN and Infinity in JavaScript

译者注

感谢@hsy0 的评论,原文做者这里没有讲清楚,毕竟一千我的一千个哈姆雷特,咱们仍是直接看标准吧 ecma-262/6.0/#sec-toprimitive

其实真实转换过程以下(做者在另外一篇文章中提到了,😂,和标准一致),就不翻译了

An object obj is converted to a number by calling ToPrimitive(obj, Number) and then applying ToNumber() to the (primitive) result. An object obj is converted to a number by calling ToPrimitive(obj, String) and then applying ToString() to the (primitive) result.

相关文章
相关标签/搜索