数据类型的强制转换(显式转换)
强制转换主要是我们主动显式的通过String()、Boolean()、Number()函数转换数据类型,分别转化为对应的字符串、布尔值、数字。
Number()
使用Number函数,可以将任意类型值转化为数字。
这里分为两种情况讨论,一种是基本类型转化,另一种是复杂类型转化。
-
基本类型转化
使用Number函数进行基本类型转化的时候,数字会转化为数字,纯数字字符串会转化为数字,如果含有无法转化为数字的部分,则会直接转化为NaN,空串('')会转为0,true会转化为1,false会转化为0,undefined会转化为NaN,null会转化为0。
//1.纯数字转化 Number(123) // 123 //2.纯数字字符串转化(纯数字字符串会被转化为数字) Number('123') // 123 //3.非纯数字字符串转化(非纯数字转化为NaN) Number('123a') // NaN //4.空串('')会转化为0 Number('') // 0 //5.布尔值true会被转化为1,false会被转化为0 Number(true) // 1 Number(false) // 0 //需要注意的是,字符串的true和false会被认定为字符串,转化为NaN Number('true') // NaN Number('false') // NaN //6.undefined会被转化为NaN Number(undefined) // NaN //7.null会被转化为 0 Number(null) //0需要注意的一点是,Number函数转化过程是很严格的,只要转化的内容中,有任何一个无法转化为数字就会返回NaN。相对来说parseInt的转化则是尽可能的将能转化为数字的转化,不能转化为数字的舍弃。
Number('123number') // NaN parseInt('123number') // 123 -
复杂数据类型的转化
相较于基本数据类型的转化,复杂数据类型转化就要复杂的多。不过大家只要记住,复杂类型的转化结果基本上为NaN,复杂的是其背后的隐式转化逻辑。只要不是单个数字的数组或空数组,其余全部情况都是NaN。
Number({})//NaN Number({a:1})//NaN Number([]) // 0 Number([1]) //1 Number(['1']) //1 Number([1,2,3]) // NaN为什么是这个结果,是因为Number的转换的背后规则非常复杂。转化主要有以下几个步骤:
- 第一步,先调用目标对象的valueOf方法,如果返回的是基本数据类型,则直接进行Number函数转化,不再执行后续步骤。
- 第二步,如果经过第一步的处理,返回的仍然是复杂数据类型,则会继续调用对象的toString方法,此时如果返回的是基本数据类型,则直接进行Number函数转化,不再执行后续步骤。
- 第三步,如果第二步中的处理最后经过toString函数转化,得到的结果仍是对象,则会抛出错误。
请看下面的转化示例:
let arr = [1,2] Number(arr) // NaN // 首先,对原目标对象调用valueOf方法 arr.valueOf() // [1,2] // 第二步,对返回的结果调用toString方法 arr.valueOf().toString() // '1,2' // 最后,上述处理结果时字符串,通过Number函数转化 Number('1,2') // NaN // 由此我们也知道了,为什么单数值数组为啥返回的是数字而不是NaN Number('1') => 1同样的,当我们将Object原型上的toString方法进行改写,让任意值的toString方法调用后,返回{},则会报错。
//重写原型方法 Object.prototype.toString = {} // 无法转化为基本数据类型,导致报错 console.log(Number({})) //TypeError: Cannot convert object to primitive value
String()
String方法,则是将任意类型值转化为字符串。
同样的,也是分为转化基本数据类型和复杂数据类型。
-
基本数据类型的转化。
使用String函数进行基本数据类型的转化,数值类型则会转化为对应的字符串;字符串转化还是原来的字符串;布尔类型则是转化为对应字符串,也就是
true转化为"true",false转化为"false";未定义值undefined则会转化为"undefined";空值null则转化为"null"。//1.数值转化 console.log(String(123));//123 console.log(typeof String(123) === 'string') // true //2.字符串转化 console.log(String('test'));//test console.log(typeof String('test') === 'string') // true //3.布尔值转化 console.log(String(true));//true console.log(typeof String(true) === 'string') // true console.log(String(false));//false console.log(typeof String(false) === 'string') // true //4.未定义值undefined转化 console.log(String(undefined));//undefined console.log(typeof String(undefined) === 'string') // true //5.空值null转化 console.log(String(null));//null console.log(typeof String(null) === 'string') // true由此可见,经过String函数转化后的值均为string类型。
-
复杂数据类型转化
String函数转化复杂数据类型如果是对象则会转化为
[object Object]的字符串,函数则会转化为对应的字符串函数体,数组则会转化为对应数组的字符串形式。function test() { console.log('1'); } console.log(String({ a: 1 })); //[object Object] console.log(typeof String(test)); //function test() {console.log('1');} console.log(String([1, 2, 3]));//1,2,3同样的,String函数转化为字符串的背后与Number函数转化过程类似,只不过第一步和第二步相较于Number函数的过程互换了一下,具体步骤如下:
- 第一步,先调用目标对象的toString方法,如果返回的是基本数据类型,则直接进行String函数转化,不再执行后续步骤。
- 第二步,如果经过第一步的处理,返回的仍然是复杂数据类型,则会继续调用对象的valueOf方法,此时如果返回的是基本数据类型,则直接进行String函数转化,不再执行后续步骤。
- 第三步,如果第二步中的处理最后经过toString函数转化,得到的结果仍是对象,则会抛出错误。
//1.正常的通过String函数转化对象 console.log(String({ a: 1 }));//[object Object] //2.拆解String函数的转化过程 console.log({ a: 1 }.valueOf());//{a:1} console.log({ a: 1 }.toString());//[object Object] //3.重写Object原型上的toString方法,使得toString方法转化后仍是复杂数据类型 Object.prototype.toString = {} console.log(String({ a: 1 }));//报错:TypeError: Cannot convert object to primitive value
Boolean()
Boolean方法则是将任意类型值转化为布尔值。
相对于Number函数和String函数,Boolean函数的转化就简单直白了很多。
除了以下七个类型值会被转化为false外,其余的值均会被转化为true。
这七个值分别是false/0n(ES2020引入的BigInt定义的0)/undefined/null/0(-0和+0)/NaN/''(空串)。
console.log(Boolean(false));//false
console.log(Boolean(0n));//false
console.log(Boolean(undefined));//false
console.log(Boolean(null));//false
console.log(Boolean(0));//false
console.log(Boolean(-0));//false
console.log(Boolean(+0));//false
console.log(Boolean(NaN));//false
console.log(Boolean(''));//false
需要注意的是,Boolean函数转化布尔值则还是本身,空对象{}、空数组[]转化后则是true。甚至连false的包装对象new Boolean(false)都是true。
console.log(Boolean({}));//true
console.log(Boolean([]));//true
console.log(Boolean(new Boolean(false)));//true
因此,我们有以下结论:
所有其他值都会被转换为 true,包括对象、数组、字符串(非空)、数字(非零)、true、false 的包装对象等。
因此,Boolean({})、Boolean([]) 和 Boolean(new Boolean(false)) 都会返回 true,因为这些值都不是上述会被转换为 false 的值。
另一方面,!(逻辑非)运算符会将 true 转换为 false,将 false 转换为 true。因此,!Boolean({})、!Boolean([]) 和 !Boolean(new Boolean(false)) 都会返回 false。
这是因为在 JavaScript 中,对象、数组、字符串(非空)、数字(非零)等都被视为“真值”,而 false、0、-0、0n、""(空字符串)、null、undefined 和 NaN 被视为“假值”。Boolean 函数和 ! 运算符用于将值转换为布尔值,以便在条件语句中使用。
自动转换(隐式转换)
下面介绍隐式转换,隐式转换本质上还是以强制转换的转换逻辑实现的,只是在使用的时候,转换过程不可见,是自动完成的。
主要有以下三种转换方式:
-
第一种情况,不同类型的数据互相运算。
123 + 'abc' //'123abc' -
第二种情况,在需要布尔值数据的地方使用非布尔值数据。
//此处的if的判断条件见常见布尔值转化,除了那七个false,其他均为true if('a'){ console.log('111')//'111' }else{ console.log('222') } -
第三种情况,对非数值类型使用一元运算符(+或者-)
+ [1,2,3] //NaN + {a:1} //NaN !!{a:1} //true! 实际上是转换布尔值的手段,有些时候开发中你会见到 !!xxx 的写法,实际上就是利用隐式转换,来将需要布尔值的地方,用这种隐式处理来实现。
自动转换实际上是js自动判断你需要什么样的类型,然后将对应的数据类型隐式转换为需要的类型。需要数字,就调用Number函数,需要字符串就调用String函数,需要布尔值就调用Boolean函数。
不过,我是并不推荐大家采用这种"取巧,简便"的方式来使用隐式转换。因为,隐式转换顾名思义就是"偷偷的,悄悄的"。可能你在开发的时候,一时用,一时爽,但是放在项目中是妥妥的定时炸弹。由于自动转换的不确定性,到了后面出现了bug,会导致错误的排查极其困难,因此在需要对应类型的地方,老老实实的使用强制转换,让其他开发者一目了然你在干什么。大大方方的使用Number函数、String函数、Boolean函数进行类型转换。
自动转换为Number类型
JS会在预期为Number类型的地方自动将目标值通过Number函数进行转化。背后的逻辑还是按照强制转换的处理方式,只不过这里是js帮我们自动转换。
只要是js预期为数值的地方,都会通过隐式转换进行处理。
console.log(1 + '2');//12
console.log(1 - '2');//-1
console.log(1 * '2');//2
console.log(1 / '2');//0.5
console.log(null + 1);//1
console.log(undefined + 1);//NaN
console.log(undefined + 1);//NaN
console.log(true + 1);//2
console.log(false + 1);//1
四则运算中,因为+ 会被js认为是拼接字符串,因此数字类型和字符串类型相加实际上是调用了String方法转化为了字符串。其余的都是数字的转换,这点需要注意。
另外,undefined会被转化为NaN,null会被转化为0。
自动转化为String类型
同样的,当js认为,预期可能是字符串的地方,就会隐式的调用String函数进行隐式转换。字符串的转换,主要发生在字符串拼接的加法运算中。当运算符的左右两边存在至少一个字符串类型数值后,运算的结果也都将是字符串类型。
console.log('1' + 0);// 10
console.log('1' + true);// 1true
console.log('1' + false);// 1false
console.log('1' + {});// 1[object Object]
console.log('1' + []);// 1
console.log('1' + function () { });// 1function () { }
console.log('1' + undefined);// 1undefined
console.log('1' + null);// 1null
由于是字符串数值的转换,因此此处运算的后半部分,实际上均通过String函数进行隐式转换,然后在进行字符串拼接。
前面数字转化的时候实际上也已经提示了,这样的运算很容易导致错误,比如你预期希望运算后的结果应该是一个Number类型,但是运算后的类型却是String类型。再次强调,不要因为开发时候偷点懒,导致后面维护的时候要你命三千!!!
let obj = {width:'100'}
obj.width + 10 //10010
let obj = {width:'100'}
Numebr(obj.width) + 10 //20
自动转化为布尔值
布尔值的转化相对于Number和String类型一样,记住会被转化为 false 的情况就可以了。转化的场景也非常有限,比如一些if语句的判断条件,一些接收值非 true 就 false 的情况。老规矩,Boolean类型,展现 false 列表。
- undefined
- null
- 0(+0/-0)
- NaN
- ''(空串)
- 0n
- false
除了上述值,其余的所有值只要是Boolean类型的转换,皆为true。通过排除上述的false值,得到的就是true。
if (!undefined && !null && !0 && !NaN && !'' && !0n && !false) {
console.log(true);
}
以上就是数据类型转换的全部内容了,如有问题欢迎指出。