Number数字类型
- 常规数字
- NaN(NOT A NUMBER):不是一个数,但是隶属于数字类型
- Infinity (无穷大值)
NaN和isNaN(检测一个值是否为非有效数字)方法
关于NaN
1.【NaN和任何值都不相等,甚至和自己都不相等;】
NaN == NaN //false
NaN === NaN //false
NaN !== NaN //true
2.【但是用Object.is(NaN,NaN)判断两个值是否相等,结果是true】
isNaN:检测一个值是否是非有效数字
- 如果【不是有效数字】则返回true
- 反之【是有效数字】则返回false
在使用isNaN进行检测的时候,其机制将首先会验证检测的值是否为数字类型,如果不是,先基于Number()这个方法,把值转换为数字类型,然后再检测。
- 如isNaN(‘10’); //为false,因为在检测前由于此机制,自动转型了
- 凡是能够转成数字之后是有效数字的,都是有效数字
//isNaN([val])
console.log(isNaN(10));//false
console.log(isNaN('AA'));//True
/*
实际上在检测之前相当于发生了:
Number('AA'); =>NaN 【转不成数字】
isNaN(NaN); =>TRUE
*/
//
console.log(isNaN('10'));//false
/*
类型转换机制
实际上在检测之前相当于发生了:
Number('10'); =>10
isNaN(10); =>false
*/
isNaN('123') //false
isNaN(123) // false
isNaN(" ") //false
isNaN('1.2.3') // true
isNaN("23px") // true
Number('"23px") = NaN
isNaN(Number('aaa')) //true Number('aaa'") = NaN
isNaN(Number(true)) // 输入1 =》false
isNaN(Number(false)) // 输入0 =》false
isNaN(Number(null)) // 输入0 =》false
isNaN(Number(undefined)) // 输入NaN =》true
自增的特殊性
由于+号的特殊性质 【可代表数学运算】,【也可代表字符串拼接】 所以在i++; i+=n; i=i+n; 这三种运算形式中也有些微的差别。 i++;和其他两种不完全一样,其代表着纯粹的数学运算
let i = '10';
i=i+1;//=>'10'+1=>'101'【结果为字符串拼接】
i+=1;//'10'+1=>'101'【结果为字符串拼接】
i++;//=>10=>10+1=>11【结果为数字11,过程为数学运算】
把其他类型值转换为数字类型
两类方法:手动转换和隐式转换
隐式转换:【浏览器内部默认要先转换为Number再进行计算的】
- isNaN([val])
- ==数学运算(特殊情况:+在出现字符串或对象的情况下不是数学运算,而是字符串拼接)【只有前++/++后/+i的时候也可能是数学运算】
- ==进行比较的时候 一些情况下会将数据类型进行转换为数字
手动转换
Number([val]): 把所有有效数字字符都进行转换(一般用于浏览器的隐式转换中)
d
+ 规则:
1 把字符串转换为数字:空字符串变为0,(第一个点除外,其作为小数点存在)如果出现任何一个非有效数字字符,结果都是NaN
console.log(Number('12.5'));//12.5
console.log(Number('12.5px'));//NaN
console.log(Number('12.5.5'));//NaN
console.log(Number(''));//0
2 把布尔转换为数字:true->1 false->0
console.log(Number(true));//1
console.log(Number(false));//0
//练习
console.log(isNaN(false)); //Number(false) =>0(是有效数字) =>false
console.log(isNaN(true)); //Number(true) =>1(是有效数字) =>false
3 null->0 undefined->NaN
null会转换为0 【null代表空对象指针,虽然代表没有,但是是有一个代表”空”的对象存在的,所以转换为Number应为0】undefined转换为NaN 【undefined代表未定义,未定义代表没有赋值,没有赋值就是”没有值”,”没有值”转换为Number的值就是NaN】
console.log(Number(null)); //=>0 console.log(Number(undefined));//=>NaN
console.log(isNaN(null)); //Number(null) =>0(是有效数字) =>false
console.log(isNaN(undefined)); //Number(undefined) =>NaN(不是有效数字) =>true
4 Symbol无法转换为数字,会报错:Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(Number(Symbol("123")))
//=>Uncaught TypeError: Cannot convert a Symbol value to a number
5 BigInt去除“n”(超过安全数字的,会按照科学计数法处理)
console.log(Number(231n)) //=>231
6 把对象转换为数字:
普通对象、正则表达式对象、日期对象….转换为数字都是NaN 只有数组对象有可能转换为数字【数组也是对象类型的!】 【空数组转换为0】 只有一项值的数组才能最终转换为数值
- 先调用对象的 Symbol.toPrimitive 这个方法,如果不存在这个方法
- 再调用对象的 valueOf 获取原始值,如果获取的值不是原始值
- 再调用对象的 toString 把其变为字符串
- 最后再把字符串基于Number方法转换为数字
Number({name:"xxx",age:5}) //=>NaN
1.=>({name:"xxx",age:5})[Symbol.toPrimitive] //=>undefined
2.=>({name:"xxx",age:5}).valueOf() //=>{name: "xxx", age: 5}
3.=>({name:"xxx",age:5}).toString() //=>"[object Object]"
4.=>Number("[object Object]") //=>NaN
console.log(Number([]));//=>0
Number([10]) //=>10
1.=>[10][Symbol.toPrimitive] //=>undefined
2.=>[10].valueOf() //=>[10]
3.=>[10].toString() //=>"10"
4.=>Number("10") //=>10
Number([10,20,30]) //=>NaN
7 其他特殊转换的案例
let time = new Date()
Number(time) //=>1625126051393
time[Symbol.toPrimitive] //=>ƒ [Symbol.toPrimitive]() { [native code] } 因为time有这个方法并且有3个参数 number / string / default 浏览器自己调用这个方法,会默认传递的实参值
time[Symbol.toPrimitive]('number') //=>1625126051393
dir(time)
VM1101:1 Thu Jul 01 2021 15:54:11 GMT+0800 (中国标准时间)
Number(new Number(10)) //=>10
new Number(10) //=> Number {10} 输出一个对象 里面包含valueof()
1.=>new Number(10)[Symbol.toPrimitive] //=>undefined
2.=>new Number(10).valueOf() //=>10 找到后不在往下走
parseInt([val],[进制]) / parseFloat([val])的使用场景
- 【注意:parseFloat不支持第二个参数!!!可以找浮点型数字】
- 【注意:parseInt可以识别各种整数(int)格式,如:8进制,10进制,16进制,所以可以接收第二个参数表示要转换为多少进制】
规则: [val]值必须是一个字符串,如果不是则先toString() 转换为字符串;然后从字符串左侧第一个字符开始找, 把找到的有效数字字符最后转换为数字「一个都没找到就是NaN」;遇到一个非有效数字字符,不论后面是否还有有效数字字符,都不再查找了; parseFloat可以多识别一个小数点
parseInt("10") //=> 10
parseInt("010") //=> 10
parseInt("10px") //=> 10
parseInt("px10px") //=> NaN
Number('10px') //=> NaN
parseInt("10PX10") //=> 10
parseInt("10.55px") //=> 10
parseInt(null) //=> NaN
parseInt(undefined) //=> NaN
parseInt(false);//=>NaN
parseInt(true);//=>NaN 如果是boolean,null,undefined类型值,则都会返回NaN
parseInt({}) //=>NaN
parseInt([]) //=>NaN
/*
parseInt/parseFloat
如果是普通对象,则都会返回NaN
({}).toString() =>"[object object]"
parseInt/parseFloat("[object object]") =>NaN
----------------------------
[].toString() =>""//空字符串
parseInt/parseFloat("") =>NaN
*/
----------------------------
console.log(parseInt([12]));//=>12
console.log(parseFloat([12.5]));//=>12.5
console.log(parseInt([12,13]));//=>12
parseInt第二个参数 讲解—-经典面试题
let arr = [27.2, 0, '0013', '14px', 123];
arr = arr.map(parseInt);
//array.map(function(currentValue,index,arr){}) js中map函数会依次处理数组中的每一个元素 并返回一个新的数组 对原来的数组不会影响
console.log(arr)
/!*
parseInt(27.2,0)
parseInt('27.2',10) -> '27' -> 把'27'看做10进制,转换为10进制 =>27
parseInt(0,1) =>NaN -> 制不在取值范围内,=>NaN
parseInt('0013',2)
parseInt('0013',2) -> '001' -> 把'001'看做2进制(2以内的数)10进制 =>1
0*2^2 + 0*2^1 + 1*2^0
parseInt('14px',3)
parseInt('14px',3) -> '1' -> 把'1'看做3进制(3以内的数 4超出三进制范围),转换为10进制 =>1
1*3^0
parseInt(123,4)
parseInt('123',4) -> '123' -> 把'123'看做4进制(4以内的数),转换为10进制 =>27
1*4^2 + 2*4^1 + 3*4^0
parseInt传递的第二个值是一个radix进制
+ radix不写或者写0,默认是10进制「如果第一个传递的字符串是以“0x”开始的,那么默认是16进制」
+ radix取值范围:2~36,不在这个范围内,处理的结果都是NaN
+ 在传递的字符串中,从左到右,找到符合radix进制的值{遇到不符合的则结束查找},把找到的值,看做radix进制,最后转换为10进制
+ 把其它进制的值转换为10进制:“按权展开求和”
*!/