前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库Number valueOf Number 强制转换
JavaScript值与类型

Number.prototype.valueOf 返回什么?自定义对象的 valueOf 会怎样影响类型转换?

Number.prototype.valueOf 返回原始类型的 number,作用是把 new Number(42) 这种包装对象拆回 42。自定义对象只要写了返回原始值的 valueOf,参与 +、-、> 这类运算时引擎就会先调它,把对象当成那个数字来算。

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

对象转原始值时,引擎按顺序找这三个方法

  1. Symbol.toPrimitive优先级最高,拿到 hint 自己决定返回什么
  2. valueOfhint 是 number 或 default 时先调它,返回对象就跳过
  3. toStringhint 是 string 时先调它,也是 valueOf 失效时的后备

valueOf 返回的如果不是原始值(比如返回 this,普通对象默认就是这样),引擎会直接忽略它,转去调 toString。两个都拿不到原始值才抛 TypeError。

核心回答

先记住这个答案

Number.prototype.valueOf() 返回的是原始类型 number。它的本职工作是拆箱:new Number(42) 是个对象,调 valueOf() 拿回原始值 42。对自定义对象来说,valueOf 是引擎做类型转换时会主动调用的钩子。对象参与 +、-、*、>、== 这类运算时,要先转成原始值,hint 是 number 或 default 时先调 valueOf,拿到原始值就用它来算。如果还定义了 Symbol.toPrimitive,它优先级更高,valueOf 就不会被调用。

  • valueOf 返回原始 number,不是对象
  • 对象参与运算前会先转成原始值
  • 数字 hint 通常先试 valueOf
  • Symbol.toPrimitive 存在时两者都不调

包装对象拆箱和自定义对象参与运算

先看 Number 本身。typeof new Number(42) 是 object,这就是包装对象。平时写 (42).toFixed(2) 时,引擎会临时包一层,调完方法就扔掉,所以我们很少直接碰到它。valueOf 就是把这层壳剥掉的方法。

一段代码看清两种用法JavaScript
const n = new Number(42)
console.log(typeof n)            // 包装对象
console.log(typeof n.valueOf())  // 拆出来的原始值
console.log(n.valueOf() === 42)

const price = {
  valueOf() { return 99 },
  toString() { return '¥99' }
}
console.log(price + 1)   // 加法用 default hint,先调 valueOf
console.log(`${price}`)  // 模板字符串用 string hint,先调 toString
console.log(price > 50)  // 比较用 number hint
查看输出与解释
object
number
true
100
¥99
true

price 只是普通对象,但写了 valueOf 之后,price + 1 得到 100,price > 50 得到 true,引擎把它当成数字 99 来算。模板字符串走的是 string hint,所以先调 toString,拿到 '¥99'。这就是 valueOf 影响类型转换的方式:它不是被你调用的,而是被运算符隐式调用的。

引擎到底按什么顺序找方法

规范里这一步叫 ToPrimitive。引擎先看对象有没有 Symbol.toPrimitive 方法,有就把 hint('number'、'string'、'default' 三选一)传进去,直接用它的返回值。没有的话,hint 是 string 就按 toString → valueOf 的顺序试,否则按 valueOf → toString 的顺序试。哪个先返回原始值就用哪个。

valueOf 返回对象会被跳过JavaScript
const weird = {
  valueOf() { return {} },   // 不是原始值,引擎直接忽略
  toString() { return '7' }
}
console.log(weird * 2)       // 走到 toString,'7' 再转数字

const both = {
  [Symbol.toPrimitive](hint) { return hint === 'number' ? 1 : 'text' },
  valueOf() { return 100 }   // 有 Symbol.toPrimitive 时根本不会被调用
}
console.log(+both)
console.log(both + '')
查看输出与解释
14
1
text

普通对象默认的 valueOf 返回的是对象自己,不是原始值,所以 {} + '' 最后会落到 toString,得到 '[object Object]'。这也解释了为什么多数对象拼字符串时表现得「只认 toString」:不是 valueOf 没被调用,而是调了但结果被丢掉了。

什么时候用 Symbol.toPrimitive 更好
valueOf 和 toString 只能各返回一种东西,控制不了 hint 细节。比如一个金额对象,希望做运算时是数字、显示时是带单位的字符串、用 == 比较时又是数字,这时写一个 Symbol.toPrimitive 按 hint 分支更直观,也不用担心两个方法谁先谁后。
回答前,多想一步

容易答错的地方

以为 + 会优先调 toString
很多人记成「遇到字符串拼接就调 toString」。实际上 obj + '' 的 hint 是 default,普通对象先调的还是 valueOf。上面 price + 1 如果换成 price + '',结果是 '99' 而不是 '¥99'。只有模板字符串、String(obj) 这类明确要字符串的场景才先调 toString。
以为 new Number(0) 是假值
包装对象是对象,对象转布尔永远是 true,这一步不走 valueOf。所以 if (new Number(0)) 会进分支。这也是不建议用 new Number() 的原因,直接用字面量或者不带 new 的 Number(x) 做转换。
以为能在任何值上调 Number.prototype.valueOf
它会检查 this 是不是数字或 Number 对象。写 Number.prototype.valueOf.call('1') 会抛 TypeError,它不会顺手帮你把字符串转成数字。
试着用自己的话回答

面试官还会怎么问?

Date 对象相加为什么得到字符串?

Date 自己实现了 Symbol.toPrimitive,把 default hint 当成 string 处理。所以 new Date() + 1 拼出一串日期文字加个 1,而 new Date() - 0 是 number hint,得到毫秒时间戳。这是内置对象里少见的「default 当 string」的例外。

[] == 0 为什么是 true?

== 两边一个对象一个数字时,对象先做 ToPrimitive。数组默认的 valueOf 返回数组本身,被跳过,接着调 toString 得到空字符串 '','' 再转数字是 0,所以相等。同样的逻辑,[1] == 1 也是 true。

怎么让一个对象不能被隐式转成数字?

写一个 Symbol.toPrimitive,在 hint 为 number 时直接抛错,就能在误用时尽早发现问题。或者让 valueOf 和 toString 都返回对象,这样转换会抛 TypeError,只是报错信息没那么清楚。

从一道题,走向一组知识

把知识连起来

值与类型

void 运算符有什么用?为什么老代码里到处是 void 0?

void 也是一个把表达式变成特定原始值的运算符,和拆箱放在一起复习「表达式最后得到什么值」。

异步与 Promise

怎么用 AbortController 取消 fetch 请求?

abort(reason) 能接收数值或 Number 包装对象;读取取消原因时,要区分原始值与对象。

参考资料

  • Number.prototype.valueOf() - MDN
  • Object.prototype.valueOf() - MDN

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

本题目录
  1. 先记住这个答案
  2. 包装对象拆箱和自定义对象参与运算
  3. 引擎到底按什么顺序找方法
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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