JS中的数据类型及其转换

130 阅读9分钟

JS的数据类型

  • 数据类型分类-可以分为两大类,即基本数据类型和引用数据类型。
    • 基本数据类型:分为7种
      • number
      • string
      • boolean
      • undefined
      • null
      • Symbol
      • bigint
    • 引用数据类型:分为2种,即object和function
      • object
        • 普通对象
        • 实例对象
        • 数组对象
        • 正则对象
        • 日期对象
        • prototype原型对象
        • ......
      • 函数function
  • 关于基本类型中的symbol的举例说明
//Symbol([value]):创建唯一值
console.log(Symbol('A') == Symbol('A'));//false
//项目中的使用方式,通常结合const常量来使用
const a = Symbol('FLAG');
  • 关于基本类型中的bigint的举例说明: 由于JS中存在最大和最小的安全数字,对于超过最大/最小安全数字的值,通常需要再在其数值后面加n变成bigint类型的数据(当然不超过范围的也是可以加n的),用以保证浏览器能够读出其数值,但是这个数值不能直接参与运算
console.log(Number.MAX_SAFE_INTEGER);//9007199254740991  最大安全数字
console.log(Number.MIN_SAFE_INTEGER);//-9007199254740991  最小安全数字
console.log((9007199254740992n)+1);//Uncaught TypeError: Cannot mix BigInt and other types

console.log(9007199254740993);//9007199254740992  浏览器输出的数值并不正确
console.log(9007199254740993n);//9007199254740993n
console.log(typeof(9007199254740993n));//bigint
console.log(BigInt(10));//10n
  • 关于基本类型中的number的一些特殊说明:NaN和Infinity
//1.NaN不是有效数字,但是属于number类型的;
//2.NaN和任何值都不相等,包括它本身
console.log(typeof NaN);//"number"
console.log(NaN === NaN);//false

//Infinity:代表无穷大的值
console.log(Infinity);//Infinity
console.log(-Infinity);//-Infinity,无穷小的值

关于NaN的检测,有两点需要注意:其一、如何检测一个值是否为有效数字?--这里就要用到isNaN([val])这个方法了。其二、要比较的两个值是否相等,若均是NaN,如何得出正确的结果?--Object中提供了一个is([值1], [值2])方法,用来检测两个值是否相等,这个方法如果监测两个NaN,则得到的结果是true,即相等。

console.log(isNaN(10));//false
console.log(isNaN('AA'));//在检测的时候,如果当前这个值不是数字类型,先隐式转换为数字类型(number),然后再检测是否为非有效数字

console.log(Object.is(10, '10'));//false
console.log(Object.is(10, 10));//true
console.log(Object.is(NaN, NaN));//true
  • 检测数据类型的方式
    • typeof运算符
    • instanceof运算符
    • constructor属性
    • Object.prototype.toString.call([value)方法

关于后三种的使用,会在后续文章中进行说明。本文只对typeof运算符进行说明:

1)typeof检测出来的结果是字符串,字符串中包含了我们对应的数据类型; 2)typeof检测null的结果是"object";但是这属于一个bug,因为计算机在底层存储的时候都是二进制,二进制以000开头的都是对象,而null存储的时候也是000开头,导致检测结果是"object"。 3)typeof不能细分对象类型(检测普通对象或者数组对象都是"object")。

数据类型转换

  1. 把其他数据类型转换为number类型
    • 能使用的办法:Number([value])和paseInt([value]) / parseFloat([value])
    • 隐式转换:
      • isNaN([value])
      • 数学运算,这个要注意特殊情况,即“+”号在出现字符串或者对象的情况下不是数学运算,而是字符串拼接
      • 在使用“==”比较的时候,有些值需要转换为数字再进行比较
  2. 把其他数据类型转换为字符串
    • 能使用的办法:toString()和String()
    • 隐式转换:一般都是调用其toString()方法
      • “+”号运算的时候,如果某一边出现字符串,则是字符串拼接
      • 把对象转换为数字的时候涉及到转换成字符串的处理,即需要先toString()转换为字符串,再去转换为数字
      • 基于alert / confirm / prompt / document.write ... 这些方式输出内容,都是把内容先转换为字符串,然后再输出的
  3. 把其他数据类型转换为布尔
    • 基于以下方式可以把其他数据类型转换成布尔
      • ! 转换为布尔后取反
      • !!转换为布尔类型
      • Boolean([val])
    • 隐式转换:
      • 在循环或者条件判断中,条件处理的结果就是布尔类型值
    • 需要牢记的规则:只有“ 0、NaN、null、undefined、空字符串 ”五个值会变为布尔的false,其余都是true
  4. 在使用“==”比较的过程中,数据转换的规则:
    • “==”号两边的数据类型一样的话,需要注意:
      • {} == {}:false 对象比较的是堆内存的地址
      • [] == []:false
      • NaN == NaN:false
    • “==”号两边的数据类型不一样的话,需要注意:
      • null == undefined:true,但是换成===结果就是false(因为类型不一致),剩下null / undefined和其他任何数据类型值都不相等
      • 字符串==对象 要把对象转换为字符串
      • 剩下如果==两边数据类型不一致,都是需要转换为数字再进行比较
  5. 加号的特殊性
    • 加号即使一边出现字符串或者对象,也不一定是字符串拼接:++i / i++ / +i 这种情况是数学运算
      let n = "10";
      //console.log(++n);//11
      console.log(+n);//10
      
      {} + 0;//0
      //左边的{}认为是一个代码块,不参与运算。运算只处理的是 +0 => 0
      
      ({}+0);//"[object Object]0"
      //参与到数学运算中
      
      0+{};//这种情况是数学运算=>"0[object Object]"
      
      +{}//=>NaN
      

针对数据类型转换的一些题目及解析

1.对象转化为布尔

console.log([] == false);//true   对象==布尔 都转换为数字(隐式转换)
console.log(![] == false);//true

/*
对象转换为数字
	先toString转换为字符串(应该是先基于valueOf获得原始值,没有原始值再去toString),再转换为数字
	[] -> '' ->0
	false -> 0
	
	![] 把数组转换为布尔类型然后取反,根据规则,
	只有“ 0、NaN、null、undefined、空字符串 ”
	五个值会变为布尔的false,其余都是true。
	而数组是对象,对象转换为布尔类型是true,再取反就是false。
*/

2.对象转化为字符串

console.log(({}).toString());//[object Object]
//对象的toString()调用的是原型上的即Object.prototype.toString()
//对象的toString()方法不是用来转换字符串的,而是用来检测数据类型的

//把其他类型的转换为字符串,一般都是直接用""包起来,只有{}普通对象调取toString是调取的Object.prototype.toString,不是转换为字符串,而是检测数据类型,返回结果是“[object Object]”

3.其他类型转化为数字

//把其他类型转换为数字
//Number的机制:
console.log(Number(''));//0
console.log(Number('10'));//10
console.log(Number('10px'));//NaN  只要出现非有效数字字符,结果都是NaN
console.log(Number(false));//0
console.log(Number(true));//1
console.log(Number(null));//0
console.log(Number(undefined));//NaN    注意
console.log(Number(Symbol(10)));//报错
console.log(Number(BigInt(10)));//10

//对象变为数字,应先valueOf,没有原始值再toString变为字符串,最后把字符串转换为数字

//parseInt机制:从字符串第一个字符开始,查找有效数字字符(遇到非有效数字字符停止查找,不论后面是否还有数字字符,都不再找了),把找到的有效数字字符转换为数字,如果一个都没找到,结果解释NaN(parseFloat比它多识别一个小数点)
//用console.log输出以下的值
parseInt("");//NaN 注意,没有找到有效数字字符
Number("");//0
isNaN("");//false   先利用Number()隐式转换
parseInt(null);//NaN 注意,没有找到有效数字字符
Number(null);//0
isNaN(null);//false 注意,先用Number隐式转换
parseInt("12px");//12
Number("12px");//NaN
isNaN("12px");//true
parseFloat("1.6px") + parseInt("1.2px") + typeof parseInt(null);//"2.6number"    
/*在JS中加号左右两边出现字符串,则变为字符串拼接(有特殊性),如果出现对象也会变为字符串拼接(因为原本,应该把对象转换为数字,但是对象转数字需要先转换为字符串,则+号遇到字符串直接变为字符串拼接 如1+[]=>"1")*/
isNaN(Number(!!Number(parseInt("0.8"))));//false
typeof !parseInt(null) + !isNaN(null);//"booleantrue"  注意,先算parseInt(null),是NaN,然后算!parseInt(null),结果是true,然后算typeof !parseInt(null),结果是boolean。isNaN(null)的运算是先把null转换成有效数字是0,而isNaN(0)结果是false,取反是true。

4.经典面试题

let result = 10 + false + undefined + [] + 'Tencent' + null + true + {};
console.log(result);

/*
10+false -> 10
10+undefined -> 10+NaN => NaN 
NaN+[] -> NaN+"" => "NaN"
"NaN"+'Tencent' -> "NaNTencent"
"NaNTencent"+null -> "NaNTencentnull"
"NaNTencentnull"+true -> "NaNTencentnulltrue"
"NaNTencentnulltrue"+{} -> NaNTencentnulltrue[object Object]
{}调用toString转换为[object Object]
结果:
	NaNTencentnulltrue[object Object]
*/

5.思考题【面试题】

let arr = [10.18, 0, 10, 25, 23];
arr = arr.map(parseInt);
console.log(arr);
/*
结果:
	[10, NaN, 2, 2, 11]
*/

/*
解析:
正常的arr.map写法
arr = arr.map((item, index)=> {
    //循环遍历数组中的某一项,就会触发回调函数
    //每一次还会传递当前项和当前项索引
});

每次遍历的时候,把回调函数执行,就是把parseInt执行
parseInt("10.18", 0);
parseInt("0", 1);
parseInt("10", 2);
parseInt("25", 3);
parseInt("23", 4);

parseInt([value], [radix]),[radix]这个值是一个进制,不写或者写0都按照10处理(特殊情况:如果value是以0x开头,则默认值不是10而是16)
进制有一个取值的范围:2~36之间,如果不在这个之间,整个程序运行的结果一定是NaN
把[value]看作[radix]进制,最后把[radix]进制转化为十进制

parseInt("10.18", 0);为例子:'10'=>10
从字符串左侧第一个字符开始查找,找到符合[radix]进制的值(遇到一个不合法的,则停止查找),把找到的值变为数字,再按照把[radix]转换成为十进制的规则处理

parseInt("0", 1);//=>NaN

parseInt("10", 2);//=>10把它看作2进制,最后转换为10进制=》2

parseInt("25", 3);//2当做三进制转换为十进制=>2

parseInt("23", 4);//23当做四进制转换为十进制=>11
*/