前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库双精度 浮点数 存储格式 指数 尾数
JavaScript值与类型

JavaScript 的 Number 在内存里是怎么存的?符号、指数、尾数各占几位?

Number 统一用 64 位双精度浮点数存:1 位符号、11 位指数、52 位尾数,值等于 ±1.尾数 × 2^(指数 - 1023)。指数位决定能表示多大多小,尾数位决定能精确到几位,所以 Number.MAX_VALUE 能到 1.8e308,安全整数却只到 2^53 - 1。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#值与类型
先看核心答案读代码示例
理解线索

双精度浮点数的三段

  1. 符号位1 位,0 是正数,1 是负数,所以才会有 +0 和 -0
  2. 指数位11 位,存「实际指数 + 1023」,全 0 和全 1 留作特殊用途
  3. 尾数位52 位,存小数点后的部分,前面默认有个不占位的 1

指数全 1 时表示 Infinity 或 NaN,指数全 0 时表示 0 和非规格化数。所以 11 位指数能用来表示普通数字的只有 1~2046 这一段。

核心回答

先记住这个答案

JavaScript 不区分整数和小数,所有 Number 都按 IEEE 754 双精度格式存成 64 位:最高 1 位是符号,接着 11 位是指数,剩下 52 位是尾数。一个数的值等于 ±1.尾数 × 2^(指数 - 1023),其中 1023 叫偏移量,用来让 11 位无符号数也能表示负指数。指数位决定数值的范围,最大约 1.8e308;尾数位决定精度,加上隐含的那个 1 一共 53 位二进制有效数字,换算成十进制大约 15~17 位。

  • 64 位 = 1 符号 + 11 指数 + 52 尾数
  • 指数存的是实际值加 1023 的偏移结果
  • 尾数前面隐含一个 1,实际精度 53 位
  • 指数管范围,尾数管精度

把一个数拆开看

直接看位最直观。DataView 可以把一个 Number 按 64 位浮点写进内存,再按整数读出来,就能拿到它的二进制。

打印几个数的三段JavaScript
function bits(x) {
  const view = new DataView(new ArrayBuffer(8))
  view.setFloat64(0, x) // 按双精度写入 8 个字节
  const all = view.getUint32(0).toString(2).padStart(32, '0') +
    view.getUint32(4).toString(2).padStart(32, '0')
  const exp = parseInt(all.slice(1, 12), 2)
  return `${x} 符号=${all[0]} 指数=${exp}(实际${exp - 1023}) 尾数前8位=${all.slice(12, 20)}`
}
console.log(bits(1))
console.log(bits(-2))
console.log(bits(6))
console.log(bits(0.1))
查看输出与解释
1 符号=0 指数=1023(实际0) 尾数前8位=00000000
-2 符号=1 指数=1024(实际1) 尾数前8位=00000000
6 符号=0 指数=1025(实际2) 尾数前8位=10000000
0.1 符号=0 指数=1019(实际-4) 尾数前8位=10011001

逐个对一下。1 写成二进制是 1.0 × 2^0,实际指数 0,加上偏移存成 1023,尾数全 0。-2 是 1.0 × 2^1,符号位变成 1。6 是二进制 110,也就是 1.1 × 2^2,小数点后的那个 1 进了尾数第一位。0.1 是 1.1001100110011… × 2^-4,尾数是 1001 无限循环,52 位存不下只能截断舍入,这就是 0.1 + 0.2 不等于 0.3 的根源。 你会发现尾数里从来不存小数点前面那个 1。规格化的二进制数第一位一定是 1,既然固定就不用浪费一位,这叫隐含位。所以 52 位尾数实际有 53 位精度。

指数管范围,尾数管精度

这两段各管一件事,面试时把它们分开讲最清楚。

指数决定能表示多大、多小
11 位指数能存 0~2047。0 和 2047 被保留,普通数字能用的是 1~2046,减掉 1023 后实际指数范围是 -1022 到 1023。尾数全 1 再配上最大指数,就是 Number.MAX_VALUE,约 1.7976931348623157e308,再乘 2 就变成 Infinity。最小的规格化正数是 2^-1022,约 2.2e-308。 指数全 0 时规则变了:不再隐含那个 1,数值变成 0.尾数 × 2^-1022,这叫非规格化数,用来在 0 附近再往下挤出一段。最小的一个是 2^-1074,也就是 Number.MIN_VALUE,约 5e-324。
尾数决定能精确到哪一位
53 位有效数字意味着,在 2^53 以内每个整数都能精确表示,这就是 Number.MAX_SAFE_INTEGER 等于 2^53 - 1 的来源。超过 2^53 后,相邻两个能表示的数之间的间隔变成 2,2 ** 53 + 1 算出来还是 2 ** 53。数越大,间隔越大,到了 1e308 附近间隔已经是天文数字了。 所以「范围大」和「精度高」是两回事:Number 能表示 1e308 这么大的数,但只能记住它的前 15~17 位十进制有效数字,后面全是近似。
指数全 1 的两种特殊值
指数全 1、尾数全 0 表示 Infinity,符号位决定正负;指数全 1、尾数不为 0 就是 NaN。尾数有 52 位,所以理论上有很多种不同位模式的 NaN,这也是 NaN 不等于自身的一个直观理解:它不是一个具体的数,而是一类「不是数」的标记。
回答前,多想一步

容易答错的地方

以为 JavaScript 有单独的整数类型
Number 只有双精度浮点这一种存储,整数只是尾数后面恰好为 0 的浮点数。真正的任意精度整数是 BigInt,它是另一种原始类型,不能和 Number 直接混算。
把 Number.MIN_VALUE 当成最小的负数
Number.MIN_VALUE 是最接近 0 的正数,约 5e-324。最小的负数是 -Number.MAX_VALUE。
以为位运算也是按 64 位做的
&、|、<< 这些位运算会先把操作数转成 32 位有符号整数再算,结果也是 32 位。2 ** 32 | 0 得到 0,就是高位被丢掉了。拿位运算取整,只适用于 32 位范围内的数。
试着用自己的话回答

面试官还会怎么问?

为什么安全整数上限是 2^53 - 1 而不是 2^53?

2^53 本身能精确表示,但 2^53 + 1 不能,会被舍入成 2^53。「安全」的意思是这个整数和它的相邻整数都能被区分开,Number.isSafeInteger(2 ** 53) 返回 false,所以上限取 2^53 - 1。

后端返回的 64 位 ID 在前端变了,怎么回事?

比如 Java 的 long 型 ID 超过了 2^53,JSON.parse 把它转成 Number 时尾数存不下,末几位被舍入,ID 就变了。常见解法是让后端把这类字段序列化成字符串,前端不要当数字处理;需要运算时再用 BigInt 转换。

为什么会有 -0?

因为符号位是独立的一位,数值部分全 0 时符号位可以是 0 也可以是 1。比如一个很小的负数下溢,或者 -1 * 0,结果就是 -0。它和 0 用 === 比较相等,但 1 / -0 是 -Infinity,用 Object.is 能区分出来。

从一道题,走向一组知识

把知识连起来

值与类型

parseInt 有哪些坑?为什么 ['1', '2', '3'].map(parseInt) 结果不对?

parseInt 解析超长数字串时,结果会被这 53 位精度截断,能看到存储格式的直接影响。

值与类型

字符串转数字,Number()、parseInt、parseFloat 和一元加号有什么区别?

字符串转成数字后都落到同一种 64 位格式里,转换函数不同,存储方式没有区别。

参考资料

  • JavaScript:值与类型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 把一个数拆开看
  3. 指数管范围,尾数管精度
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑