论坛首页 Web前端技术论坛

「译」JavaScript 的怪癖 1:隐式类型转换

浏览 3034 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-04-17  

原文:JavaScript quirk 1: implicit conversion of values

译文:「译」JavaScript 的怪癖 1:隐式类型转换

译者:justjavac


零:提要

[此贴子是 javascript 的 12 个怪癖(quirks) 系列的第一篇。]

JavaScript 是非常宽容的,「来者不拒」,不在乎什么类型。 例如,它如果想要接受数字,它并不拒绝其他类型的值,而是试图把它们转换成数字:

> '5' - '2'
3
> '5' * '2'
10

自动转换为布尔值通常不会引起问题,而且往往很有用(译注:比如在C语言里,根本就没有布尔类型。by @justjavac)。 即使如此,这些隐式转换也会引起怪癖(quirks)。 但是当自动转换为字符串时,可能会引起问题。

一:隐式转换为布尔:“truthy”和“falsy”

当 JavaScript 需要一个布尔值时(例如:if 语句),任何值都可以被使用。 最终这些值将被转换为 true 或false

下面的值被转换为 false

  • undefined, null
  • Boolean: false
  • Number: -0, +0, NaN
  • String: ''

所有其他值都认为是 true。 被转换成 'false' 的值我们成之为 falsy,被转换成 'true' 的值我们成之为 truthy。 您可以使用 Boolean 来测试一个值到底被转换成了什么。

Boolean 将其参数转换为布尔值(boolean):

> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true

二、字符串的隐式转换

在 Web 开发中,我们经常得到字符串值,实际上我们期望的却是数字或者布尔值。 例如,用户输入的表单中的数据。 如果你忘了对这些字符串进行显式的转换,那么 JavaScript 会令你感到惊讶,主要体现在两个方面:

  1. 首先,系统不会有任何警告。
  2. 其次,这些值将被自动转换,但确实错误的。

例如,加运算符(+),就有这方面的问题,因为只要其中一个操作数是字符串,那么它就执行连接字符串的操作(而不是加法操作,即使它们是数字)

在下面的 JavaScript 代码中,我们本来预期是把 1 和 5 相加。 但是,我们使用了字符串 '5' 和 '1' 。

> var x = '5';  // 错误的假设:x 是一个数字

> x + 1
'51'

此外,还有一些看似是 false 的值,如果转换成字符串,却成了 'true'。

例如:false

> Boolean(false)
false
> String(false)
'false'
> Boolean('false')  // !!
true

例如: undefined.

> Boolean(undefined)
false
> String(undefined)
'undefined'
> Boolean('undefined')  // !!
true

三、对象的隐式转换

只有在 JavaScript 表达式或语句中需要用到数字或字符串时,对象才被隐式转换。 当需要将对象转换成数字时,需要以下三个步骤:

  1. 调用 valueOf()。如果结果是原始值(不是一个对象),则将其转换为一个数字。
  2. 否则,调用 toString() 方法。如果结果是原始值,则将其转换为一个数字。
  3. 否则,抛出一个类型错误。

第一步示例:

> 3 * { valueOf: function () { return 5 } }
15

第三步示例:

> function returnObject() { return {} }
> 3 * { valueOf: returnObject, toString: returnObject }
TypeError: Cannot convert object to primitive value

如果把对象转换成字符串时,则转换操作的第一步和第二步的顺序会调换: 先尝试 toString() 进行转换,如果不是原始值,则再尝试使用 valueOf()

四、相关阅读

  1. JavaScript中,{}+{}等于多少?
  2. JavaScript:将所有值都转换成对象
  3. 为什么 ++[[]][+[]]+[+[]] = 10?
   发表时间:2013-04-23  
支持一个下,说下等号的规律吧:
等号(==)
如果比较的两个元素类型不一样时要进行类型转换,规则如下:
1. 如果有一个是Boolean类型,一个是数字类型,则将Boolean类型转化成数字,false转化成0,true转成1
2. 如果有一个是字符串类型,一个是数字类型,则把字符串转化成数字
3. 如果有一个是字符串类型,一个是对象类型,则把对象转化成字符串(toString())
4. 如果有一个是对象类型,一个是数字类型,则把对象转化成数字
5. null和undefined相等
6. 不能把null和undefined转化成其他值
7. 如果有一个为NaN,等号返回false,非等号返回true。即使两个都是NaN,等号任然返回false
8. 如果两个元素是对象,这比较的是他们的引用值。如果俩个运算数指向同一个对象,那么等号返回true,不相等
1 请登录后投票
   发表时间:2013-04-24  
thc1987 写道

1. 如果有一个是Boolean类型,一个是数字类型,则将Boolean类型转化成数字,false转化成0,true转成1
2. 如果有一个是字符串类型,一个是数字类型,则把字符串转化成数字
3. 如果有一个是字符串类型,一个是对象类型,则把对象转化成字符串(toString())
4. 如果有一个是对象类型,一个是数字类型,则把对象转化成数字

8. 如果两个元素是对象,这比较的是他们的引用值。如果俩个运算数指向同一个对象,那么等号返回true,不相等


这5条可以合起来理解和记忆。

== 运算符的类型转换, 按照  数值 -->  字符串   -->  对象引用 的次序转换。

0、null和undefined相等。否则,
1、如果任一个操作数是数值(包含布尔值),就按照数值比较。否则,
2、如果任一个操作数是字符串,就按字符串比较。否则,
3、按对象引用比较。
1 请登录后投票
   发表时间:2013-04-24  
受教了,简单明了
0 请登录后投票
   发表时间:2013-05-05  

还有一个混乱的转换:

new Boolean(true) == true  结果是 true
!!new Boolean(true)        结果是 true

!!new Boolean(false)       结果也是true!!!
new Boolean(false) == false 结果是true!!!


~~~~~
==转换时,按照布尔值(或者数值比较),会调用Booelan对象的valueOf()比较
!!转换时,直接按对象是否为null比较。

1 请登录后投票
   发表时间:2013-05-06  
sswh 写道

还有一个混乱的转换:

new Boolean(true) == true  结果是 true
!!new Boolean(true)        结果是 true

!!new Boolean(false)       结果也是true!!!
new Boolean(false) == false 结果是true!!!


~~~~~
==转换时,按照布尔值(或者数值比较),会调用Booelan对象的valueOf()比较
!!转换时,直接按对象是否为null比较。



还真是...
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics