为何JS热量计算函数在iOS端返回NaN,桌面端却正常运行?
问题分析与解决方案
核心问题:iOS输入法智能引号导致高度解析失败
iOS默认输入法会自动将输入的单引号转换成弯引号(’),但你的ftTocm函数仅用split("'")(直引号)分割字符串,导致分割后ft[1]为整个原输入内容,parseInt转换后得到NaN,最终引发后续所有计算结果为NaN。
其他潜在触发NaN的问题
- 无输入合法性校验:若用户输入空值、非数字内容,
parseInt/parseFloat会返回NaN,直接带入计算会导致异常。 - 变量重复声明:
lbsToProtein中已声明calorieIntake和proteinGrams,后续又用var重复声明,属于不良编码习惯。 switch无默认分支:若weightGoal不是1/2/3,calorieIntake和proteinGrams会保持undefined,计算后得到NaN。
修复步骤
1. 兼容智能引号的高度解析
修改ftTocm函数,同时处理直引号和弯引号,并增加格式校验:
function ftTocm(height) { console.log(height) // 统一替换直/弯引号后分割 var ft = height.replace(/['’]/g, "'").split("'"); // 校验分割后格式是否合法 if (ft.length < 2) return NaN; var feet = parseInt(ft[0]); var inches = parseInt(ft[1]); // 校验数字转换是否成功 if (isNaN(feet) || isNaN(inches)) return NaN; var cm = (feet * 12 + inches) * 2.54; console.log("cm", cm); return cm; }
2. 增加输入合法性校验
在submit函数中提前校验所有输入,无效时提示用户:
function submit() { var lbs = parseFloat(document.getElementById('lbs-input').value); var age = parseInt(document.getElementById('age-input').value); var height = document.getElementById('height-input').value; var goal_input = document.getElementById('select'); var excercise_input = document.getElementById('excercise'); var excercise = parseInt(excercise_input.value); var weightGoal = parseInt(goal_input.value); // 基础输入校验 if (isNaN(lbs) || lbs <= 0 || isNaN(age) || age <= 0 || !height) { alert("请输入有效的体重、年龄和身高"); return; } var cm = ftTocm(height); if (isNaN(cm)) { alert("请输入正确格式的身高,例如:5'10"); return; } if (isNaN(weightGoal) || ![1,2,3].includes(weightGoal)) { alert("请选择有效的体重目标"); return; } if (isNaN(excercise) || excercise < 1 || excercise >3) { alert("请选择有效的运动强度"); return; } var info = lbsToProtein(lbs, weightGoal, cm, age, excercise); document.getElementById('calories').innerHTML = info[1] + ' calories'; document.getElementById('protein').innerHTML = info[0] + ' grams'; document.getElementById('form').style.cssText = 'display: none;'; document.getElementById('results').style.cssText = 'display: block !important;'; }
3. 修复lbsToProtein的潜在问题
移除重复变量声明,增加默认分支处理异常情况:
function lbsToProtein(lbs, weightGoal, cm, age, excercise) { var kgs = lbs / 2.205; var calorieIntake; var proteinGrams; switch (weightGoal) { case 1: //维持体重 calorieIntake = (kgs * 13.397) + (cm * 4.799) - (age * 5.677) + 88.362 + excercise; proteinGrams = kgs * 0.8; break; case 2: //增重 calorieIntake = ((kgs * 13.397) + (cm * 4.799) - (age * 5.677) + 88.362) + 700 + excercise; proteinGrams = kgs * 1.35; break; case 3: //减重 calorieIntake = (((kgs * 13.397) + (cm * 4.799) - (age * 5.677) + 88.362) - 700) + excercise; proteinGrams = kgs * 0.8; break; default: // 处理异常目标值 calorieIntake = NaN; proteinGrams = NaN; break; } // 移除重复的var声明 calorieIntake = Math.round(calorieIntake); proteinGrams = Math.round(proteinGrams); console.log("Protein: "+proteinGrams+"g"); console.log('Calorie Intake: '+calorieIntake+'cal', (typeof calorieIntake)); var info = [proteinGrams, calorieIntake]; console.log(info) return info; }
测试建议
- 在iOS设备上用默认输入法输入
5'10格式的身高,验证解析是否正常 - 测试空输入、非法格式输入,确认能弹出提示而非返回NaN
内容的提问来源于stack exchange,提问作者RaidLucky
相关产品推荐
相关产品推荐

