位置消息中,经度或纬度为 0,页面却提示“请先选择位置”。一个常见原因是用 if (!longitude || !latitude) 判断是否填写:JavaScript 的数值 0 会进入这个分支,合法的零值就与缺失数据混在了一起。
以米米商聊为背景,已整理的手机端资料包含位置消息。本文借这一功能讨论输入校验,不断言产品存在下述问题,也不推断产品使用的地图服务、坐标体系或定位策略。所有坐标都是独立合成测试数据,没有获取、展示或上传任何用户的真实位置。
1. 零值、未填写和定位失败是三种状态
经度 0 或纬度 0 本身可以有明确的地理含义。不能因为数字为假值,就认定位置不存在;也不能在定位失败后填入 0,再把它当成取得了有效定位。
本例把经度限定在 -180~180、纬度限定在 -90~90,单位为十进制度。它们是不同字段,不能仅凭“两个数都在范围内”判断字段是否对应正确。浏览器 Geolocation API 的字段与单位可分别参考 longitude 文档和 latitude 文档。本文不调用该 API,也不申请定位权限。
| 输入或业务状态 | 本例怎样处理 | 需要区分的含义 |
|---|---|---|
| 经度或纬度为数值 0 | 允许通过范围校验 | 零是数字,不是缺失标记 |
| 字段不存在、null、空白文本 | 拒绝 | 没有有效数值输入 |
| NaN、Infinity、越界数字 | 拒绝 | 不是约定范围内的有限坐标 |
| 定位请求失败 | 由定位流程单独处理 | 不能默认填成坐标 0 |
如果既有协议明确使用某个数值作为特殊标记,接入层需要按协议识别并转换成明确状态,不能让通用数值校验器猜测。本文示例没有为 0 设置特殊业务含义。

2. 先检查输入形式,再转换成数字
把所有输入直接交给 Number(),也会引入歧义:空字符串、纯空白文本或 null 可以被转换成 0。另一方面,parseFloat() 会接受某些带有非数字后缀的文本前缀,不能用来证明整个输入都是坐标。
MDN 的 Number 文档列出了类型转换规则。这里选择先验证输入类型与完整文本形式,再执行转换,随后检查有限值和范围。
本例接受有限的 number,以及去掉首尾空白后的十进制文本。文本可以带正负号,可以写成 .5;整数部分最多三位,小数部分最多八位。不接受指数、十六进制、分组逗号、单位后缀或全角数字。
这些是教学用的表单输入规则,不是产品协议或通用坐标标准。字符串限制八位小数,也不意味着定位精度达到某个距离。数值输入不经过文本格式检查,两种输入的边界需要明确说明。
3. 用具名字段保留经纬度含义
下面函数只负责解析与范围检查,输出新的具名字段对象。它不读取设备位置,也不转换坐标体系。
function parsePosition(input) {
if (input === null || typeof input !== "object" || Array.isArray(input)) {
throw new TypeError("position must contain named fields");
}
function read(value, name, min, max) {
let number;
if (typeof value === "number") {
number = value;
} else if (typeof value === "string") {
const text = value.trim();
if (!/^[+-]?(?:\d{1,3}(?:\.\d{1,8})?|\.\d{1,8})$/.test(text)) {
throw new TypeError(`invalid ${
name} text`);
}
number = Number(text);
} else {
throw new TypeError(`invalid ${
name} type`);
}
if (!Number.isFinite(number) || number < min || number > max) {
throw new RangeError(`${
name} outside allowed range`);
}
return number === 0 ? 0 : number;
}
return {
longitude: read(input.longitude, "longitude", -180, 180),
latitude: read(input.latitude, "latitude", -90, 90)
};
}
function toLongitudeLatitudeArray(input) {
const point = parsePosition(input);
return [point.longitude, point.latitude];
}
这里将 -0 统一返回为 0,只是让示例输出一致,不是对地理位置做修正。错误信息只包含字段名和错误类型,不附带坐标值。
传入对象中的其他字段不会进入结果。例如精度、采集时间、来源或坐标体系信息,需要由对应的数据模型保存与校验,不能因为本函数没有返回它们,就在整个业务流程中丢弃这些信息。
数组适配函数明确按“经度、纬度”输出。以 GeoJSON 为例,RFC 7946 第 3.1.1 节规定位置数组前两个值的顺序是经度、纬度。该适配器只重组字段,不执行坐标转换;只有接入方已经确认来源符合目标格式的坐标约定,才应把结果用于该格式。
4. 让零值和边界值进入同一组测试
将下面演示与上一段放在同一个 JavaScript 文件中执行。所有数值均为合成案例,不代表真实设备位置。
const zero = parsePosition({
longitude: 0, latitude: " 0 " });
console.assert(zero.longitude === 0 && zero.latitude === 0);
const point = parsePosition({
longitude: "+.5", latitude: "-1.25" });
console.assert(point.longitude === 0.5 && point.latitude === -1.25);
const edge = parsePosition({
longitude: 180, latitude: -90 });
console.assert(edge.longitude === 180 && edge.latitude === -90);
const ordered = toLongitudeLatitudeArray({
longitude: 0, latitude: 45 });
console.assert(ordered[0] === 0 && ordered[1] === 45);
let rejected = false;
try {
parsePosition({
longitude: "", latitude: 0 });
} catch {
rejected = true;
}
console.assert(rejected);
console.log(ordered);
第一项会通过,因为 0 是本例允许的数值;最后的空字符串会被拒绝,不会先转换成 0。其余验证还覆盖缺失字段、非有限值、八位小数边界、带后缀文本和越界输入。
经度与纬度的顺序尤其需要单独测试。把示例的两个值反过来,得到经度 45、纬度 0,仍然都在范围内,但代表另一处位置。范围检查无法从两个合法数字中自动猜出交换错误,所以内部使用具名字段,只有在接口边界才转换成数组。
5. 数值合法,不等于位置可信或坐标体系正确
| 本例能确认的事情 | 不能仅靠数值确认的事情 |
|---|---|
| 输入属于允许的数值或文本形式 | 是否来自真实设备,是否由用户选择 |
| 两个字段都是有限值且没有越界 | 坐标体系是否与地图服务一致 |
| 数组按约定的经度、纬度顺序输出 | 采集时间是否足够新,精度是否适用 |
| 0 与缺失输入被区分处理 | 定位权限、失败原因与用户授权状态 |
一对坐标通过范围检查,不能证明它使用了目标地图需要的坐标体系。两个体系中的数值都可能落在同样的经纬度范围内;格式正确也不表示地图显示就一定正确。接入前应明确来源与目标坐标约定,需要转换时采用相应的转换流程,而不是只修改字段名。
同样,保留更多小数位并不能提高原始定位精度。显示精度、数据表示与设备测量精度是不同的问题。若消息需要记录采集时间或精度,应把这些元数据的含义定义清楚,避免把历史位置误当成当前所在位置。
失败时也应保留明确状态:未选择、请求被拒绝、暂时不可用等状态,应由实际流程决定。不要把它们都变成 { longitude: 0, latitude: 0 },然后继续当成成功结果发送。
6. 接入时分别验收字段、来源与展示
先在表单或接口边界校验输入,再在适配层核对字段顺序与坐标约定,最后检查消息预览和地图展示。服务端也需要按自己的契约校验,不能仅依赖客户端函数。
本例的配套验证包括 0、负零、空值、数字类型、文本格式、经纬度边界和数组顺序,并用固定种子的 500 组合法合成输入检查解析与字段保留。它只测试独立解析函数,没有申请定位权限,没有调用地图服务,也没有验收真实产品客户端。
页面验收时还应覆盖:一项为 0、两项均为 0、缺少一项、定位失败后重试,以及预览和最终消息是否使用了同一份具名数据。排查时避免在日志中附带不必要的真实位置内容。
位置校验首先要回答“有没有有效数值”,再回答“这些数值在当前协议中表示什么”。把零值从缺失状态中分离出来,并保留字段、来源和坐标约定,才能避免一个简单的真假值判断改变位置消息的含义。
本文由 AI 辅助整理,独立示例经过本地验证。产品背景只引用已整理的手机端位置消息资料;工程建议不代表产品坐标体系、定位能力或内部实现。