js中的数据类型:
1.原始值类型:
- number
- string
- boolean
- symbol
- undefiend
- null
- bigint
2.对象类型:
- 标准普通对象
- 标准特殊对象
- 非标准特殊对象
- 可调用对象(函数对象)
【JS中的数据类型和检测:】https://www.jianshu.com/p/1c83b872154f
其他类型转为Number:
一般来说有两大方案:
一、Number([val])
- 一般情况下我们不会手动来用Numer来转(但是写了也没问题)
这种方式一般都是通过隐式转换来完成的
什么是隐式转换?就是浏览器自己通过Nunber()来转换
什么情况下会存在隐式转换呢?常用的有以下三种:
@1. 数学运算
10-'5' = 5 // => Number('5')
10 + '5' = '15' // 字符串拼接
@2. isNaN检测
isNaN(true) // false => isNaN(Number(true))
isNaN('12px' ) // true => isNaN(Number('12px')) (Number([val]) val有过有一个无效字符,结果就是NaN)
@3. ==比较
两边类型不一样,要默认转换成一样的类型进行比较
.......
- 其他类型转换为Number的一些规则:
@1. 字符串转为数字:空字符串变为0,如果出现任何非有效数字都是NaN
image.png
@2. 把布尔烈性转为数字:true -> 1,false -> 0
@3. null -> 0 undefined -> NaN
image.png
@4. Symbol无法转换为数字,会报错:
@5.bigInt去除'n'(超过安全数字的,会按照科学计数法处理)
image.png
所以一般情况下bigInt还是转为字符串比较合适
@6.把对象转换为数字:
- 先调用对象的Symbol.toPromitive 这个方法,如果不存在这个方法
- 再调用对象的 valueof 获取原始值,如果获取的值不是原始值
- 再调用对象的 toString 把其变为字符串
- 最后再把字符串基于 Number方法转换为数字
举个例子:
let obj = {
name: 'zhangsan'
}
console.log(Number(obj)) // -> NaN
执行步骤:
obj[Symbol.toPromitive] :没有Symbol.toPromitive,执行valueOf()
obj.ValueOf() :执行valueOf()得到的不是原始值,是对象:{name: "zhangsan"},再去执行toString()
obj.toString() -> "[object Object]"
Number("[object Object]") -> NaN
let arr1 = [10],
arr2=[10,20]
console.log(Number(arr1 )) // -> 10
console.log(Number(arr2 )) // -> NaN
image.png
image.png
普通标准对象{}和标准特殊对象[]都没有toPrimitive属性,下面来看一个有toPrimitive属性的
let time = new Date()
console.log(Number(time))
image.png
- 经验证time[Symbol.toPrimitive]的值是个函数,说明日期对象有这属性
- 接下来把这个属性执行 ,直接执行会报错,如下图
- 所以这个属性执行的时候要传值(hint),传递的值有3种:'number','string','default',传的值不同,结果也不同
image.png
浏览器会帮我们判断,如果是转成数字,会传'number',如果是转成字符串,会传'string',如果浏览器也不确定,传'default'
image.png
上图中,浏览器帮我们处理1时,实际过程就是2,处理3时,实际过程就是4
接下来再通过一个例子来验证下这个规则:
给obj写个[Symbol.toPromitive]属性,执行代码看下结果
let obj = {
name:'张三',
[Symbol.toPrimitive](hint) {
console.log(hint)
return 10
}
}
console.log(Number(obj)) // 'number' Number(10) -> 10
console.log(String(obj)) //'string' String('10') -> '10'
console.log(obj.toString()) // '[object Object]'
确认验证结果:
1.如果有[Symbol.toPrimitive]这个属性,是溪岸执行这个属性
2.执行[Symbol.toPrimitive]时,浏览器会默自己判断hint传的值是什么值
3.注意:直接调用obj的toString()时,走的是Object.prototype.toString().call(obj)这套逻辑,这不是把它转换为字符串,所以不走Symbol.toPromitive
4.对象不管是转数字还是转字符串,都是按:[Symbol.toPromitive],valueOf(),toString(),数字的话再加个Number()这顺序来转换的
再来看个例子
let arr = [10]
arr[Symbol.toPrimitive] = function(hint) {
console.log(hint)
return 0
}
console.log(arr.toString()) //'10' 直接调用原型的方法,不会走 Symbol.toPrimitive这个逻辑
console.log(arr + '') // 'default' '0'
- 第一个console.log()中,arr也是直接调的toString(),同上个例子一样,也只直接调的类的原向上的方法,所以结果是'10'
- 第二个console得到的结果是‘default’ 和字符串'0',是因为:数组+字符串,需要把arr隐士转换为字符串[需要走Symbol.toPromitive这套逻辑,hint为‘default’],然后再进行字符串拼接
为什么hint是'default'不是'string'呢?因为+号既是数学运算,也是字符串拼接,浏览器此时不确定是哪种情况,所以hint是default,
所以,把一开始的规则补充冲总结下就是:
当我们把对象隐士转换为数字或者字符串的时候[使用的方法:Nymber()/String()],会有一套自己的处理逻辑:
@1、检测Symbol.toPrimitive,如果有这个方法,浏览器会把方法执行,传递hint[根据场景不一样,浏览器默认传递的值也不同:'number','string','default' ];如果没有这个方法,则进行下一步;
@2、基于valueOf获取原始值,如果获取的不是原始值,再进行下一步;
@3、基于toString获取字符串
@4、如果需要转的是数字,则再次把字符串转为数字即可
注意:如果是直接对象.toString(),详单与直接调用第三个步骤[直接调用所属类原型上的toString方法],此时直接获取字符串,不会走这四步的逻辑
二、parseInt([val],[radix])和parseFloat([val])
- 这种情况就不是隐式转换了,也就是我们说的手动转换,这两个的处理规则就和Number完全不一样了
- 规则:[val]必须是一个字符串,如果不是则先转为字符串:然后从第一个字符开始查找,把找到的有效数字转为数字,一个都没找到就是NaN;遇到一个非有效字符,不论后边是否是有效数字,都不用再查找了;parseFloat比parseInt多识别一个小数点
测试题
console.log(parseInt('10'))
console.log(Number('10'))
console.log(parseInt('10px'))
console.log(Number('10px'))
console.log(parseInt(null))
console.log(Number(null))
- 第一组:10 10
- 第二组:10 NaN
console.log(parseInt('10px'))遇到p停止查找,所以是10
console.log(Number('10px'))有一个非有效字符就是NaN - 第三组 NaN 0
console.log(parseInt(null)):先把null转为字符串,结果是空字符串"",parseInt从左都右,一个有效字符否没找到,所以是NaN
.
网友评论