问题描述:
今天在项目开发中,在使用三元表达式对数据进行判断展示(如下简例)
const a = Number('m').toFixed(2)
const b = Number('n').toFixed(2) // m、n:任意数字
const c = a > b ? b : a;
遇到一个问题,判断出的结果有时候会出现问题,结果不正确,虽然解决了这个bug,但是没明白缘由,最后刨根问底一下,进行案例复现,结果发现是toFixed()的影响……
javaScript中Number对象的toFixed()返回的数据类型原来一直是string啊!!![捂脸],我一直以为number调用的方法,返回的是Number类型,学到了学到了
补充:然后又再次复现发现
一个问题' 2 '>' 11 ' == true ? 啊啊啊……没看错,true,是true 🤧 JS是如何进行隐式类型转换的?
错误对比:
提示:
先看一下发现问题时的错误对比:就很直观
这样是不是很清晰的可以看出是受到了toFixed()的影响,也被
JS的隐式类型转换深深上了一课……哎,鄙人不才,对js了解还甚浅啊
原因分析:
提示:
在这里进行简单的问题复现,
浅显记录一下避坑过程,看看你是不是也遇到过类似的问题
:
例如:对原有数据进行修改,且不得超过某一数据
好比: 结果(c)= 投入(a) > 预算(b) ?预算 :投入
我们正常开发中使用toFixed()方法,一般是用到Number()转化为数字类型并想保留位数对吧
先看一个例子:
const a = Number("2").toFixed(2)
const b = Number("5").toFixed(2)
const c = a > b ? b : a;
console.log(c)
此时 console.log(c) 会打印出什么呢,肯定是我们预想要的' 2.00 '对吧,一直到这一步,如果功能没有出现bug,我们肯定会觉得一切正常,所有的用法都是我们自己想的那样(😂对,不错就是我,觉得Number() 使用toFixed()后的结果依旧是还是number数字类型
)
漏漏漏~大漏~特漏啊兄弟们,这玩意让我学到了toFixed()方法返回的数据类型是string类型
让我们在看一个例子:
const a = Number('2').toFixed(2)
const b = Number('11').toFixed(2)
const c = a > b ? b : a;
console.log(c)
这次你觉得 console.log(c) 会打印出来什么?' 2.00 ' ?反正我潜意识中觉得打印出来会是' 2.00 ',但是兄弟们实际上不是这样的,打印出来的反而是 ' 11.00 ',哎,这时候bug就出现了,三元表达式的结果异常了,没有达到我们想要的预期,这时候又陷入了深思,莫非三元表达式自己没用明白?莫慌莫慌……我们一点点排查
【三元表达式(运算符)小科普( 仅供小萌新参考,大佬请忽略,大大佬看出问题请指教)】
====普及线====
语法为:条件表达式 ? 表达式1 : 表达式2
说明:( ? )问号前面的位置(条件表达式)是判断的条件,判断结果为bool型,为true时调用表达式1,为false时调用表达式2。
逻辑:“如果条件表达式成立或者满足则执行表达式1,否则执行表达式2。”
不难看出三元表达式与if-else有点关联:
if(条件表达式 ){
表达式1
}else{
表达式2
}
是不是也满足上述逻辑?没毛病
三元表达式与if-else的联系与区别:
1)三元表达式可以简化if-else条件判断语句;
2)三元表达式要求必须返回一个结果;
3)if后的代码块可以有多个语句;
=====End=====
从上面我们可以看出,哎,三元表达式好像并没有问题,那为什么' 2 ' > ' 11' 比较的结果会是true?难道……好吧,我百度了一下,JS存在隐式数据类型转换,是不是很眼熟,js诚不欺人啊!!! 正是前面toFixed()的影响使得返回结果是string,触发了js的
隐式数据类型转换
在js中,当运算符在运算时,如果两边数据类型不一致,CPU就无法计算,这时编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算,这个过程是不可见的,所以称为隐式数据类型转换。
对于关系操作符( <, >, <=, >=)也有相应的隐式转换规则,关系操作符的操作值可以是任意类型的,因此在使用非数值类型参与比较时编译器会进行隐式类型转换,在实现数据比较:
- 如果两个操作值都是数值,则进行数值比较;
- 如果两个操作值都是字符串,则比较字符串对应的字符编码值( Unicode 编码);
- 如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较;
- 如果一个操作数是对象,则调用valueOf()方法(如果对象没有valueOf()方法则调用toString()方法),得到的结果按照前面的规则执行比较;
- 如果一个操作值是布尔值,则将其转换为数值,再进行比较;
注:NaN是非常特殊的值,它不和任何类型的值相等,包括它自己,同时它与任何类型的值比较大小时都返回false。
按我们通常的思维是不是会觉案例中的数据会转为数字再比较 c = 2 > 11 ? b : a; 然后输出'2.00',其实不然,通过上述关系操作符隐式类型转换规则不难看出此时的' 2 ' 和 ' 11 ' 被转换成了对应的字符编码值及50和49进行比较 c = 50> 49 ? b : a; 输出结果:'11.00'。
JavaScript中用charCodeAt()来获取字符编码
// JavaScript中用charCodeAt()来获取字符编码
const a = Number('2').toFixed(2)
const b = Number('11').toFixed(2)
const c = a > b ? b : a; // c:'11.00'
//案例中将操作符两边都转为字符编码再进行比较
'2'.charCodeAt() // 50
'11'.charCodeAt() // 49
//所以出现了 '2' >'11' 为true 的情况
当然,上述案例中你不使用 toFixed(2),也就不会遇到上述问题,一点毛病都没有
const a = Number('2')
const b = Number('11')
const c = a > b ? b : a;
console.log(c); // c:2
结个尾:
这个案例不管函数方法的使用还是隐式类型转换,都是拜javaScript的福。不过还挺好,从一个坑让自己从中加深了两个知识点的了解,但是要强调的一点是我们在做类似运算比较时可以事先确认好数据类型及后续你要展示的形式,不要像我在本案例中最终想要的结果就是保留两位小数的,然后为了简洁使用三元表达式做处理,使用的又不恰当,导致了问题,其实可以这样
// 1
const a = Number('2').toFixed(2);
const b = Number('11').toFixed(2);
const c = Number(a) > Number(b) ? b : a;
// 2
const a = Number('2');
const b = Number('11');
const c = a > b ? b.toFixed(2): a.toFixed(2);
当然了具体要根据自己项目情况,这里只是案例,仅供参考~仅供参考,如有不妥欢迎留言指正
至此,刨根结束, toFixed()的错还是隐式数据类型转换的错?漏~no~漏,Js大大没有错,错的是学术不精的鄙人……才疏浅薄,只能做片面解读,希望对你有所帮助
关于js隐式类型转换的相关知识还要感谢博主的文章‘2‘>‘10‘==true? JS是如何进行隐式类型转换的?_前端南玖的博客-CSDN博客