JavaScript简单函数未按预期运行,原因是什么?
嘿,我来帮你理清楚这个问题——你踩了一个新手很容易犯的坑:混淆了Number.isNaN()和全局isNaN()这两个方法的核心差异!
原代码失效的原因
你原以为!Number.isNaN(x)的意思是“如果x是数字则为真”,但其实完全不是这么回事。Number.isNaN()是ES6新增的严格判断方法,它的规则特别简单:只有当传入的参数严格等于NaN(注意是严格相等===)时,才会返回true,其他所有值——不管是字符串、普通数字、甚至undefined——都会返回false。
看你的原代码:
let theNumber = 'god' function numberCheck(x) { if (!Number.isNaN(x)) { // 对于'god':Number.isNaN('god')返回false,!false就是true,进入if分支 // 对于12:Number.isNaN(12)返回false,!false也是true,同样进入if分支 console.log('You picked a number') } else { console.log('why won\'t this log'); } }
所以不管你传字符串还是数字,这个判断条件永远为true,自然永远执行第一个console.log。
关于你修复后的代码
你换成全局isNaN()后,输出符合了预期,但其实这里有个“逻辑巧合”:
全局isNaN()的行为是先尝试把传入的参数转换成数字,如果转换结果是NaN,就返回true,否则返回false。
你的修复代码里,判断逻辑和输出内容其实是写反的:
let theNumber = 'god' function numberCheck(x) { if (isNaN(x)) { // 'god'转数字会变成NaN,所以isNaN('god')返回true,进入if分支 console.log('You picked a number') // 这里本该输出“不是数字”的提示 } else { console.log('why wont this log'); // 12转数字是有效数字,isNaN(12)返回false,进入else } }
刚好你把两个console.log的内容写反了,才得到了你想要的输出结果——但逻辑本身是不对的,以后很容易出问题!
给你几个正确的写法
根据你的需求(判断输入是否是有效数字),可以选下面几种更严谨的方案:
1. 判断是否是严格的数字类型(排除字符串形式的数字)
如果你只想接受12这种数字类型,不接受'12'这种字符串数字,可以用typeof结合Number.isNaN():
let theNumber = 'god' function numberCheck(x) { if (typeof x === 'number' && !Number.isNaN(x)) { console.log('You picked a number') } else { console.log('That\'s not a valid number'); } } numberCheck(theNumber) // 输出:That's not a valid number numberCheck(12) // 输出:You picked a number
2. 判断是否可以被转换成有效数字(支持字符串形式的数字)
如果你想接受'12'这种能转成数字的字符串,可以用全局isNaN()的取反,同时处理一些特殊边界情况:
let theNumber = 'god' function numberCheck(x) { // 排除空字符串、null这些会被误判的情况 if (x === '' || x === null) { console.log('That\'s not a valid number'); return; } if (!isNaN(x)) { console.log('You picked a number') } else { console.log('That\'s not a valid number'); } } numberCheck(theNumber) // 输出:That's not a valid number numberCheck('12') // 输出:You picked a number numberCheck(12) // 输出:You picked a number
3. 最严谨的数字判断(推荐)
用Number.isFinite(),它会自动排除NaN、Infinity、-Infinity这些无效数字,只对有限的有效数字返回true:
let theNumber = 'god' function numberCheck(x) { if (Number.isFinite(x)) { console.log('You picked a number') } else { console.log('That\'s not a valid number'); } } numberCheck(theNumber) // 输出:That's not a valid number numberCheck(12) // 输出:You picked a number numberCheck(Infinity) // 输出:That's not a valid number
作为新手,区分全局方法和Number对象的静态方法是很重要的,多测试几种边界值,就能慢慢摸清楚它们的行为啦!
内容的提问来源于stack exchange,提问作者Jacob Tartaglia

