JavaScript强制类型转换(三)

本文深入探讨JavaScript中的类型转换,包括隐式与显式转换,详细讲解toString方法、其他类型转换成Boolean及Number的过程,以及parseInt和parseFloat的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

强制类型转换

JavaScript的值具有类型,所以JavaScript也有强制类型类型转换,对于动态语言,强制类型转换总是发生在运行时。强制类型转换分为隐式和显式,有一种区分方法是:如果我一眼就能看懂了这是强制类型转换,那么他就是显式的,否则,他就是隐式的。比如下面:

var a = 1
b = "" + a
c = String(a)

一、toString方法

JavaScript的几乎所有数据类型的实例都具有toString方法,这可以理解成转换成字符串的类型转换。

//1.Number
1..toString() //=> "1"
//2.Boolean
true.toString() //=> "true"
//3.Object
({}).toString() //=>"[object Object]"
//4.Function
(function(){}).toString() //=> "function (){}"
//5.Symbol
Symbol("1").toString() //=> "Symbol(1)"

因为 null和undefined没有toString()方法,String类型toString还是本身,所以以上的例子基本包含了JavaScript所有数据类型(介绍typeof那里的全部)的toString方法。当然,这并不是全部,因为还有一些引用类型的toString方法结果并不是”[object Object]”。

//1.Array
([1,2]).toString() //"1,2"
//2.Date
new Date().toString() //=>"Sun Dec 09 2018 21:00:29 GMT+0800 (中国标准时间)"
//3.Error
new Error("error").toString() //=>"Error: error"
//4.RegExp
new RegExp(/regexp/).toString() //=>"/regexp/"

再加上上面的例子,基本就包含了所有的类型的toString方法,class定义的默认是继承了Object,所以为返回”[object Object]”。这里补充一点,我之前说过var a = 1和var a = new Number(1)这2种给变量赋值是有区别的,这里1..toString()仍然使用的是Number的toString方法

Number.prototype.toString = function(){return "toString已被修改!"}
1..toString() //=>"toString已被修改!"

toString还有一个特点就是它支持进制,toString接收一个数值参数,如果处理的对象是Number类型,那么会先将其转换成对应的进制,然后再输出字符串结果:

(11).toString(8) //"13"
new Number(11).toString(8) //"13"
("11").toString(8) //"11"

最后是一个总结加补充: 
1.一般情况下其他类型转换成字符串类型都有自带的toString方法,转换出来是什么结果前面已有例子,我们也可以重写这些toString函数达到我们想要的效果,重写:Number.prototype.toString = function(){return "toString已被修改!"},一定要修改原型链上的toString方法。 
2.null和undefined没有toString方法,但是我们可以这样String(null)和String(undefined),这相当于调用的String函数,而不是toString方法

二、其他类型转换成Boolean

其他类型转换成布尔值我们没有直接的toBoolean方法,但是在if(a) 中,a会被强制转换成Boolean值,类似的也有Boolean方法(不常用,一般布尔值是在if条件里面的,默认就会被转换),比如Boolean(a)。转换成布尔值的规则相对比较简单,只需要记住哪些是false就行了,因为其他都是true。并且更有趣的是引用类型都是true,只有基本类型才有可能是false。

  • +0,0,-0,NaN
  • null                          //注意”null”是true,但是null是false
  • undefined               //同上
  • ""                             //空字符串
  • false                        //这个本身就是布尔值false

这里有一点需要注意的是下面的情况:

var a = new Boolean(false)

if(a){

console.log("想不到吧,会进入循环!")

}

console.log(a.toString()) //=>false

 

上面的例子a会进入循环,因为这里a是一个引用类型的值,而不是真正的布尔值。所以这也是不要使用封装对象给变量赋值的原因,它总有一些意想不到的情况发生。

最后再补充一个很简单的强制转换写法 !!a,这样就能将其他类型转换成布尔值。

三、其他类型转换成Number

我想转换成Number用到最多的应该是Number函数(因为没有toNumber方法-。-),Number仅接收一个参数,如果可以转换成合法数字就返回转换的那个数字,如果不是合法数字就返回NaN,他一般都是处理字符串转换成数字。(数字是指int和float)

Number(1.1) // =>1.1

Number("1.1") // =>1.1

Number("1.a") // =>NaN

Number(undefined) //=>NaN

Number(Symbol(""))    //报错

Number(true) //=>1

Number(false) //=>0

Number(new Boolean(true)) //=>1,最好还是不要让这种情况的转换发生

Number(new Boolean(false)) //=>0,最好还是不要让这种情况的转换发生

Number({}) //=>NaN 引用类型基本都是转换成NaN,但是有2个例外

Number(new Date) //输出的当前时间的时间戳,这个是例外

Number([]) // =>0

Number([1])  //=>1

Number([1,2]) //NaN,对于数组,如果数组的长度为1,那么取第一个元素,将其转换成Number类型,但是还是需要注意一些例外

Number([undefined])     //=>0
Number([true])          //=>NaN
Number([false])         //=>NaN

//下面是一些转换成0的情况
Number() //=>0
Number(null)/=>0
Number("") //=>0
Number([]) // =>0

//Number无法指定进制,但是它有对进制的支持
Number("0x11")    //17
Number("0o11")    //9
Number("0b11")    //3

Number的原理:

1.首先判断参数是否是基本类型(封装对象赋值的变量当成引用类型),如果是基本类型,那么按照对应的处理。

2.如果不是基本类型,那么调用其valueOf方法,看valueOf返回的值是否是基本类型。如果valueOf返回的值是基本类型,按基本类型处理。

3.否则,调用toString方法,判断toString方法返回的值是否是基本类型

 

 

Number(new Boolean(true))     //=>1

//valueOf是基本类型的情况
Boolean.prototype.valueOf = function(){return "233"}
Number(new Boolean(true))    //=>233
Boolean.prototype.valueOf = function(){return "[]"}
Number(new Boolean(true))    //=>NaN

//valueOf不是基本类型的情况
Boolean.prototype.valueOf = function(){return []}
Number(new Boolean(true)) //=>NaN,因为toString()的结果是 "true" 而Number("true")是NaN
Boolean.prototype.toString = function(){return "233"}
Number(new Boolean(true)) //=>233
Boolean.prototype.toString = function(){return []}
Number(new Boolean(true)) //=>报错

//下面是一个数组的例子
Array.prototype.valueOf = function(){return true}
Number([]) //=> 1

//valueOf不是基本类型的情况
Array.prototype.valueOf = function(){return []}
Number([2]) //=>2,因为[2].toString()的结果就是"2"
Array.prototype.toString = function(){return "233"}
Number([2]) //=>233
Array.prototype.toString = function(){return []}
Number([2]) //=>报错


对于Number函数我们可以做如下总结:

  • 引用类型基本全都是NaN,但是Date是时间戳,数组会取第一个元素进行判断。
  • 基本类型里面除了undefined和不合法的数字字符串是NaN以外其他都可以转换成正常数字。
  • 前面提到的那些,合法数字字符串转换成对应的数字,true转换成数字是1,其他(空串,null,false,不传参数)都是0

除了Number当然还有其他函数也是将其它类型转换成数字的:parseInt,parseFloat。

parseInt(转换成整数)

与其说parseInt是转换,还不如说它是解析字符串成整数。它的第二个参数是可选参数,可以选择进制,默认是10进制(ES5之前会根据第一位字符进行判断,比如parseInt("08") 输出0,因为以0开头默认按8进制解析,这个真实情况我没验证,ES5默认是10进制)。它处理的有效位数是截至第一个非法字符,这么描述我自己也不懂,还是看几个例子:

parseInt("16px")    //=>16,因为p是非法字符,所以转换的有效字符串是"16"
parseInt("px16")    //=>NaN,因为第一个字符就是非法的

//下面的几种可以和Number对比一下
parseInt("")        //=>NaN
parseInt(true)      //=>NaN
parseInt(false)     //=>NaN
parseInt(null)      //=>NaN
parseInt(undefined) //=>NaN

//下面是几种引用类型
parseInt(new Date)  //=>NaN
parseInt({})        //=>NaN
parseInt([])        //=>NaN
parseInt([1])       //=>1
parseInt([1,2])     //=>1,这里的区别是当数组具有多个元素时,多余的会被忽略,没有元素返回NaN
parseInt([2,1])     //=>2

//下面观察解析其他进制的情况
parseInt("0xFF")    //=>255
parseInt("0xFF",16) //=>255
parseInt("011")     //=>11,这个并没有当成8进制
parseInt("0o11")    //=>0,这个也没有当成8进制(console.log(0o11) => 9)
parseInt("0o11",8)  //=>0,还是0
parseInt("11",8)    //=>9
parseInt("0b11")    //0

 我们还需要深究一下parseInt的原理,不然下面的现象解释不了。

parseInt(1/0,19) //=>18因为 1/0 = Infinity , 19进制 I 是有效字符 ,parseInt("I",19)结果18

parseInt(0.000008)    //0 因为这相当于"0.000008",小数点后不算有效字符
parseInt(0.0000008)   //8 因为这等价于 "8e-7" ,e后不算有效字符 

parseInt(parseInt,16) //15 因为function(){...}第一位f是有效字符

原理:除了直接的字符串和直接的整数,parseInt会将参数转换成字符串类型,转换方法是调用对应变量的toString方法,然后再进行解析。

Function.prototype.toString = function(){return "666"}
parseInt(parseInt)    //=>666

Number.prototype.toString = function(){return "666"}
parseInt(1)                //=>1
parseInt(new Number(1))    //=>666,因为a = new Number(1),这里的a是引用类型

String.prototype.toString = function(){return "666"}
parseInt("1")                //=>1
parseInt(new String(1))      //=>666,因为a = new String(1),这里的a是引用类型

parseFloat原理和parseInt差不多,只是除了能解析整数以外还能解析浮点数。最后还要补充一个Number的快捷的方式代码如下:

+"12.34"    //=>12.34
1+ +"12.34" //13.34,注意中间的空格

它的解析方式和Nunber差不多。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值