Javascript 类型转换
Javascript 类型转换
介绍
Javascript (ECMA Script)是一种弱类型的语言.这并不意味着它没有数据类型,只是变量或者Javascript对象属性不需要一个特定类型的值分配给它或者它始终使用相同的值.Javascript中的变量同样支持自由类型转换成为适用(或者要求)的内容以便于使用.
弱类型的Javascript不会按照程序员的愿望从实际的变量类型到所需要的数据类型转换,例如一个非常常见的错误,在浏览器脚本中,从表单控件中获取用户将要输入的一个数值类型的变量与另一个数值变量的和.因为变量类型在表单控件中是字符串类型(计时字符串序列包含一个数字)这种尝试将会添加那个字符串到变量,即使这些值碰巧是一些数字,结果在第二个变量将会被转换为字符串类型,在最后只会把从表单控件中得到的变量添加到第一个字符串末尾.
这个问题实际上就是"+"操作符,数字和与字符串连接问题.操作结果完全取决于被操作参数,只有在 +
操作两者参数都为数值时才会作取和操作,否则,参数就会被自动转换为字符串进行连接操作.
接下来讨论在Javascript 工作中在类型转换操作的变量返回情况.下表反应了在Javascript 中所有的类别,比如 123e-2 作为数值类型,对于不同的类型赋予了不同的颜色.在接下来的章节中,我们将遵循这一规则.
如果你接受这个页面的变量类型CSS样式设置,下表就是关于不同变量与不同颜色的搭配关系.操作符将会成为 typeof
这样的样式.( null
类型将会返回 "object"
当现实中 null
指定了某个对象
Key |
---|
string |
number |
boolean |
object |
function |
null |
undefined |
布尔值同样会有高亮背景 true
或者 false
.
转换到布尔类型 (Boolean)
当表达式是 if
以及其他一些判断情况时,类型转换的结果将会是布尔型为了用于判断.这些判断包括逻辑运算比如 与 (&&
), 或 (||
) 以及 非 (!
). 非运算转换变量为波尔型并且如果变量是波尔型-真.那么将返回假,反之将返回真.两次非操作将会返回等同于变量转换成为波尔型的值.
var boolValue = !!x;
这个技巧将会后面将会用到.
另外一种可选择的方法就是把目标作为参数传递给Boolean 构造函数.
var boolValue = Boolean(x);
-1.6 | -0 | +0 | 1 | 1.6 | 8 | 16 | 16.8 | 123e-2 | -Infinity | +Infinity | NaN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
!!col | true | false | false | true | true | true | true | true | true | true | true | false |
当数值类型转换为布尔型时,数值零将会变成假而其他数值将会变成真.除开特殊数值 NaN
(Not a Number), NaN
被用于其他类型转换到数值类型时当没有返回一个有意义的数值时. NaN 总是返回假. 无论是无限大还是无限小或者是有限数值,只要不是零,在转换为布尔型时总是返回 true
..
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
!!col | false | true | true | true | true | true | true | true | true | true | true | true | true | true | true |
字符串类型转换规则是简单的,字符串类型转换到布尔型除了空字符串外都是返回真,空字符串返回假.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
!!col | false | false | true | false | true | true |
对于其他类型, undefined
和 null
将会返回假, Object以及function类型总是返回真.
当需要判断某一对象是否是未定义的对象时,这是最有价值的功能.如果调用未定义的变量(undefined 或者 null) 将会产生错误.当这些都还不确定时(通常是网页浏览器所关心的)为了避免代码产生错误,需要对对象进行 if
判断.建议把对象作为表达式,转换为波尔型,如果返回 false
则说明对象不存在,如果返回 true
则说明对象存在.
if(document.documentElement){ scrollX = document.documentElement.scrollLeft; }
两次非操作可以判断对象是否能被使用.
var hasDocEl = !!document.documentElement; ... if(hasDocEl){ scrollX = document.documentElement.scrollLeft; }
转换到字符串类型 (String)
如上文所说的,其他类型转换到字符串类型常常来自于 + 操作符,无论其中一个参数是否为数值.最简单转换到字符串的方法是,把目标变量连接到一个空字符串上.这种技巧的结果对应如下表.
另外一种可选择的方法就是把目标作为参数传递给 String
构造函数.
var stringValue = String(x);
-1.6 | -0 | +0 | 1 | 1.6 | 8 | 16 | 16.8 | 123e-2 | -Infinity | +Infinity | NaN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
"" + col | -1.6 | 0 | 0 | 1 | 1.6 | 8 | 16 | 16.8 | 1.23 | -Infinity | Infinity | NaN |
注意上面数值 123e-2
已经被转换为字符串 "1.23"
,因为已经由科学计数法转换为普通表达式了.然而,Javascript 的本质数值类型是来自于IEEE的双精度浮点类型,这就意味着只能储存有限的精度.数学操作结果可能只能产生近似的值,当他们转换到字符串时,可能会收到意想不到(指坏的)的结果.所以常常需要设置特定的定制函数用以获得可接受的结果.这种类型转换机制难以保证正常结果.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
"" + col | undefined | null | true | false | [object Object] | function(){ return; } |
当一个对象或者函数被转换为字符串时,他们的 toString
方法将会被调用.默认会执行 Object.prototype.toString
以及Function.prototype.toString
除 除非重写 "toString" 方法.把一个函数转换到字符串,返回结果并非是必须的.Function.prototype.toString
方法就能完成大部分需要,它将会返回 "host objects" 和方法(这个对象和方法取决于不同环境,比如 DOM 元素).
转换到数值型 (Number)
转换到数值类型,特别是由字符串转换到数值类型,有很多通用的方法,任何数学操作方法除了加法( +
)都会执行类型转换.所以转换字符串类型到数值类型可以使之与一个数值操作,比如减去零或者乘以一.
var numValue = stringValue - 0; /* or */ var numValue = stringValue * 1; /* or */ var numValue = stringValue / 1;
但是 +
(取正)操作还是可以转换字符串类型到数值类型.因为他不做任何计算操作,所以这种方法是最快的.
顺便一提,相反数操作 -
同样也会执行类型转换,使得目标成为相反的结果.
var numValue = (+stringValue);
/* 这是不必要的,在 + 操作后已经被添加了括弧,只是为了使得代码更容易被人理解并且使得他很清楚.特别是避免了与添加和连续操作相混淆.
比较:
var n = anyNumVar++ + +stringVar + ++anotherNumVar;
- 与 -
var n = (anyNumVar++) + (+stringVar) + (++anotherNumVar);
^^ ^ ^^
(后自增) + (取正数) + (前自增)
*/
最终 +
(取正)操作是最快的转换字符串类型到数值类型的方法.传递给 Number
构造函数一个参数,它将会执行类型转换并且返回一个数值类型.
var numValue = Number(stringValue);
Number构造函数是最慢的类型转换方法,但是当速度不是所考虑的关键时,使用它能够使得代码变得很干净.
接下来的表格展示了执行 +
(取正)操作时所对应的结果.通过先前的选了,其他转换操作同样会返回相同的结果.(下表 Octal代表八进制,Hex代表十六进制. 译者注)
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+col | 0 | -1.6 | 0 | 1 | 1.6 | 8 | 16 | 16.8 | 1.23 | 10 | 16 | 255 | -10 | NaN | NaN |
需要考虑从的是当转换字符串类型到数值类型时,如果需要从不是表示数值的字符串中返回结果.空字符串将会返回数值零,这对于程序可能是无害的也可能是致命伤害,但这是应该注意得到可能会发生的.在其他各项中都是遵循Javascript格式化结构的,可能对于十六进制数有些疑问,因为最后还是将他们表示成为了十进制.然而字符串想要被解析为十六进制必须被认为十六进制(以 0x
或者 0X
起头).字符串无法被识别为 NaN
.它是 isNaN
函数返回结果.字符串类型数字是一个指数格式 ("123e-2"
) ,不再被理解为负号.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
+col | NaN | 0 | 1 | 0 | NaN | NaN |
Objects 和 functions 总是被转换为 NaN
. undefined
与 null
同样代表没有东西,但是只有 null
被转换为数值零.可能是因为他们先被转换为波尔型,然后才转换为数值型,在上文中转换为波尔型的结果已经很清楚了, null
转换为波尔型将会返回 false
. 它将会变为数值零. 他们几乎都不必转换为数值类型.他们如何进行转换的真正意义在于为了考虑一些偶然的结果,要转换一个字符串时,结果返回的是他们这些(或者是由于进行了一些数学计算操作才返回了这些).
解析数值
一种转换字符串类型到数值类型的可以选择方法是使用全局函数,它是一个已经设计好的解析字符串返回数值的函数. parseFloat
函数接受一个字符串参数,返回一个单精度数值.这是一种快速的转换非字符串参数的方法.
字符解析函数获取每一个字符直到遇到不属于数值的字符,然后返回它已获取的数值.这个特性常常被用于开发中.比如一个代表CSS长度的字符串,它的值是 "34.5em"
parseFloat
函数不会理会 "em"
因为这些字符无法与之前的数字产生有效的值.它将会返回 34.5.这个CSS字符串中的数字部分.
parseFloat
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
parseFloat(col) | NaN | -1.6 | 0 | 1 | 1.6 | 8 | 16 | 16.8 | 1.23 | 10 | 0 | 0 | -10 | 0 | NaN |
对于 parseFloat
解析空字符串将会返回 NaN
,是因为空字符串不属于数字表达式.指数可以被解析,由0起头的八进制不会阻止字符串解析为十进制数.十六进制数却因为 "x"
无法作为数字被解析而停止解析而返回一个零.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
parseFloat(col) | NaN | NaN | NaN | NaN | NaN | NaN |
非字符串类型转换成为快速转换,作为一个字符串传递给 parseFloat
.当那些类型转换作为字符串时不在是正常的结果,它的解析结果是 NaN
. Objects 和 functions 可能有自定义 toString
方法返回字符串将会被解析成为数值,这是一个特殊的要求.
parseInt
parseInt
函数的工作方式和 parseFloat
有些相似.不同之处在于它是尝试把字符串转换为整型数值,只能辨认几个少数作为数字的符号.
parseInt
函数偶尔被用作转换单精度浮点数值类型为整型.由于这种转换首先要从字符串类型转换到单精度数值类型所以是不太适用的,另外,由于它会产生一些错误,所以变得非常没有效率,比如 2e-200
这个科学计数法的数值正确的返回因该是零,但是 parseInt
返回 2
.并且由于是Javascript 格式化,数值常常返回的是一些近似值.比如 1/2 + 1/3 + 1/6 = 0.9999999999999999 ,这个表达式的结果的近似值应该是 1 ,但 parseInt
竟会返回 0.
可以取得近似值的 Math.round
, Math.ceil
和 Math.floor
都比较合适这个工作,为了取得结果,表达式将会被作为32位有符号整型,这个规则同样适用于下面这些情况.(译者注 Math.round
函数执行的是常见的四舍五入,0.4以及一下将会被忽略,0.5以及以上将会被加1. Math.ceil
函数在只要有小数的情况是就加1 . Math.floor
函数则无论小数大小都会被忽略.由这些函数的定义可知 parseInt 方法对于小数采取的是同 Math.floor 一样的处理方式)
-1.6 | -0 | +0 | 1 | 1.6 | 8 | 16 | 16.8 | 123e-2 | -Infinity | +Infinity | NaN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col) | -1 | 0 | 0 | 1 | 1 | 8 | 16 | 16 | 1 | NaN | NaN | NaN |
在结果中我们可以很明显的看到函数执行时先把参数转换为字符串型然后才进行解析.注意那个 123e-2
值,它就相当于数值 1.23
,执行类型转换时转换到字符串类型 "1.23"
,所以这项在上表中看起来很奇怪,但是这是正确的.
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col) | NaN | -1 | 0 | 1 | 1 | 8 | 16 | 16 | 123 | 8 | 16 | 255 | -8 | -16 | NaN |
进行格式化到整型中当字符串是八进制或者十六进制数时, parseInt
函数可以以按符合Javascript代码规则的方式解析他们,甚至当他们带有负号时.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
parseInt(col) | NaN | NaN | NaN | NaN | NaN | NaN |
As parseInt
type-converts its non-string arguments to strings it always produces the same results for boolean
, null
, undefined
, object and function arguments as parseFloat
(assuming objects and functions do not have custom toString
methods).parseInt
和 parseFloat
一样在接受非字符串的其他类型参数时,都会产生相同的结果.比如 boolean
, null
, undefined
, object and function (假定这些 objectes 和 functions 都没有自定义 toString
方法).
parseInt 指定基数参数
这是一个少有让人满意的功能, parseInt
允许我们自定义接受参数的进制格式.比如以0开头的字符串很少会被用于八进制格式化(特别是在用户输入中). 为了处理这类问题, parseInt
接受第二个参数,基数.它可以指出第一个字符串参数要被如何解析.特别指出,第二个参数如果是 10 , parseInt
函数将解析第一参数字符串只能为十进制.
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col, 10) | NaN | -1 | 0 | 1 | 1 | 8 | 16 | 16 | 123 | 10 | 0 | 0 | -10 | 0 | NaN |
八进制字符串现在已经被解析为 10 了,十六进制字符串则变成了 0 ,因为解析步骤停止在了 "x"
字符上.
Number bases 2 to 36 can be used with parseInt
. The following is base 16. parseInt
第二参数的合法值为 2 到 36.接下来是基于16进制的.
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col, 16) | NaN | -1 | 0 | 1 | 1 | 8 | 22 | 22 | 4670 | 16 | 16 | 255 | -16 | -16 | NaN |
十六进制 0x
可以被识别出,在基于十六进制数时.
最后,尝试下基于3进制.
-1.6 | -0 | +0 | 1 | 1.6 | 8 | 16 | 16.8 | 123e-2 | -Infinity | +Infinity | NaN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col, 3) | -1 | 0 | 0 | 1 | 1 | NaN | 1 | 1 | 1 | NaN | NaN | NaN |
结果很明显,数字 8
输出 NaN
是因为 "8"
字符在三进制数中无法被解析,这和下面一行中空字符串参数产生了相同的结果.
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
parseInt(col, 3) | NaN | -1 | 0 | 1 | 1 | NaN | 1 | 1 | 5 | 3 | 0 | 0 | -3 | 0 | NaN |
ToInt32
ToInt32
是一个内置函数,虽然很有用,但是无法像 parseInt
一样被直接调用.用它转换Javascript变量到数值有一些不同寻常的方式.但是它能在一些有限的情况下被使用.位操作,比如按位OR(|
)和 按位AND (&
) 操作数值时,在使用它们操作时能被转换为数值类型.但是他们只工作在32位有符号的整形中,所以我们可以通过调用内置函数 ToInt32
返回已转换的32位有符号整形变量(进行类型转换).
结果就像是 parseInt
函数调用后,只是结果被限定为32位,因此都是数值,而没有 NaN
或者 Infinity
.
就算是用空值进行操作,结果返回的也是一个数值,使用一个位运算不会印象结果,却可以调用 ToInt32
函数.下表表示经过按位OR 0 运算后的结果.
-1.6 | -0 | +0 | 1 | 1.6 | 8 | 16 | 16.8 | 123e-2 | -Infinity | +Infinity | NaN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
col|0 | -1 | 0 | 0 | 1 | 1 | 8 | 16 | 16 | 1 | 0 | 0 | 0 |
NaN
和 ±Infinity
变成了0, 浮点数被缩短成了整形.
"" (empty string) |
"-1.6" | "0" | "1" | "1.6" | "8" | "16" | "16.8" | "123e-2" | "010" (Octal) |
"0x10" (Hex) |
"0xFF" (Hex) |
"-010" | "-0x10" | "xx" | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
col|0 | 0 | -1 | 0 | 1 | 1 | 8 | 16 | 16 | 1 | 10 | 16 | 255 | -10 | 0 | 0 |
ToInt32
把字符串类型变量将原被应该被转换为 NaN
的结果变成了 0.
undefined | null | true | false | new Object() | function(){ return; } | |
---|---|---|---|---|---|---|
col|0 | 0 | 0 | 1 | 0 | 0 | 0 |
操作后甚至 undefined
, objects 和 functions 都被转换为 0,注意,布尔值 true
被转换成了数值 1.
转换用户输入
大多数的结构都是为了获取用户输入. <input type="text">
和 prompt
.例如在表单中他们的结果是字符串类型.即使期望用户只输入数字,他们仍然可能输入仍和东西(至少他们可能会输入一个制表符).如果想要把字符串类型转换为数值类型,上文的最后一种方法是最合适的.但是有时仍然会有一些错误的输入难以发现和控制.
把字符串类型转换为数值类型一种更有利的方法是使用正则表达式(Regular Expression),使得字符串确保可以被正确的格式化.它也可以为剔除一些字符串变量而服务.
正则表达式例子
/^\d+$/ //所有数字 /^\s*[-+]?\d+\s*$/ //连续的数字 /^\d{1,5}$/ //由1到5组成的数字 /^\d+\.\d\d$/ //Money /^\d+(\.\d{2})$/ //Money /^\d{1,3}(,\d\d\d)*\.\d\d$/ //带逗号的 money - 12,432.57 // 可带逗号和不带逗号的 money - 12,432.57 or 12432.57 /^\d{1,3}(,\d\d\d)*\.\d\d$|^\d+\.\d\d$/
翻译: Dreampuf (http://www.macgoo.com/myblog/)
原文链接:http://www.jibbering.com/faq/faq_notes/type_convert.html