如何在JavaScript中正确校验输入值是否超出C# long取值范围
JavaScript 原生 Number 类型采用IEEE 754双精度浮点数存储,可精确表示的整数上限为 2^53 - 1 = 9007199254740991,而C#的 long.MaxValue 为 9223372036854775807,已经超出JS的精确整数表示范围。
你原有代码的问题在于:从输入框拿到的value是字符串类型,和数字字面量9223372036854775807做大小比较时,JS会隐式把两边值转成Number类型,此时9223372036854775808转成Number后和9223372036854775807的存储值完全一致,所以比较结果返回false,校验失效。
另外你调用$(this).valid()不生效,是因为jQuery Validate默认的range校验规则同样基于JS Number实现,本身就无法正确处理超出2^53的整数边界。
方案1:纯字符串比较(无任何依赖,兼容所有浏览器)
不需要把输入值转成数字,直接通过长度判断、逐位字符对比判断是否越界,完全避开精度丢失问题,可直接写在blur事件逻辑中:
// C# long 类型上限的字符串形式 const LONG_MAX_STR = '9223372036854775807'; const value = $(this).val().trim(); // 先校验输入是否为合法正整数格式 if (!/^\d+$/.test(value)) { $('#divValueError').text("请输入合法正整数!"); return false; } let isOverRange = false; // 长度超过19位肯定大于long.MaxValue(long.MaxValue固定为19位数字) if (value.length > LONG_MAX_STR.length) { isOverRange = true; } else if (value.length === LONG_MAX_STR.length) { // 长度相等时逐位比较字符大小 for (let i = 0; i < LONG_MAX_STR.length; i++) { if (value[i] > LONG_MAX_STR[i]) { isOverRange = true; break; } else if (value[i] < LONG_MAX_STR[i]) { break; } } } if (value <= 1 || isOverRange) { $('#divValueError').text("Invalid Value!"); return false; } // 校验通过清空错误提示 $('#divValueError').text(""); return true;
如果需要支持校验负数(对应long.MinValue = -9223372036854775808),参照正数判断逻辑对称实现即可。
方案2:使用BigInt类型(现代浏览器适用,写法简洁)
如果项目不需要兼容IE等老旧浏览器,可以直接使用ES2020新增的BigInt类型,它支持精确表示任意长度整数,代码更简洁:
const LONG_MAX = 9223372036854775807n; const value = $(this).val().trim(); if (!/^\d+$/.test(value)) { $('#divValueError').text("请输入合法正整数!"); return false; } const inputVal = BigInt(value); if (inputVal <= 1n || inputVal > LONG_MAX) { $('#divValueError').text("Invalid Value!"); return false; } $('#divValueError').text(""); return true;
方案3:适配[Range]注解的客户端校验
如果希望沿用ViewModel上[Range]注解的自动客户端校验,只需要重写jQuery Validate的range校验方法,把内部的数字比较逻辑替换成上述任意一种越界判断逻辑即可,之后不需要单独绑定blur事件,失焦、表单提交时都会自动触发校验。
注意:所有校验逻辑都不要直接把输入值转成Number类型后再和long边界值比较,只要数值超过2^53,转Number后必然出现精度丢失,会导致校验结果错误。
内容的提问来源于stack exchange,提问作者Ram P

