在所有 Number 对象的原型方法中,toString() 可能是使用频率很高但往往被无意识调用的一个。很多开发者知道数字可以变成字符串,但容易忽略这个方法的另一个实用功能——进制转换。通过传入 radix 参数,你可以把十进制数字轻松转换为二进制、八进制或十六进制字符串,这在处理颜色值、权限码或者底层数据编码时经常派上用场。
语法结构
数字对象.toString(radix)
参数说明
-
radix:可选参数。一个整数,取值范围是 2 到 36(包含边界)。它指定了目标字符串应当采用的进制基数。如果省略该参数,默认值为
10,即按十进制转换。
返回值特征
-
返回一个字符串,内容是指定进制下的数字表示。
-
如果调用该方法的对象不是有效数字(例如
null或undefined),会抛出TypeError。
核心机制:从数值到字符串的转换逻辑
toString() 做的事情本质上就是把内存中的数值按照给定的进制规则,映射为一串人类可读的字符序列。十进制数字 12,在二进制下是 "1100",在八进制下是 "14",在十六进制下是 "c"。这些不同的字符串形态指向的是同一个数值,只是表示方式不同。
个人经验分享:在做前端开发时,我经常需要把 RGB 颜色值中的某个通道从十进制转成十六进制。比如 rgb(255, 128, 64) 要转成 #ff8040。早期我习惯写一个函数手动计算余数然后拼字符串,代码又长又容易出错。后来发现直接用 colorValue.toString(16) 一行就能搞定,而且浏览器原生支持,性能比手写循环好得多。如果转换结果只有一位(比如 10 转成 "a"),再配合 padStart(2, '0') 补零就完成了。这就是我为什么现在很少自己造进制转换轮子的原因——toString(radix) 足够简洁可靠。
日常场景与代码示例
示例 1:基础类型转换(十进制转字符串)
最常规的用法是不传参数,直接将数字变成字符串。
let positiveNum = 50;
let negativeNum = -50;
let decimalNum = 50.25;
console.log(positiveNum.toString()); // 输出:50
console.log(negativeNum.toString()); // 输出:-50
console.log(decimalNum.toString()); // 输出:50.25
可以看到,正数、负数、小数都能准确转换为对应的字符串形式,符号和小数点都会保留。
示例 2:数值拼接中的行为差异
这是一个经典的对比案例,展示了调用 toString() 前后,加法运算符 + 的行为变化。
let x = 50;
let y = 30;
// 情况一:两个数字直接相加,执行数学运算
let mathResult = x + y;
console.log("数学相加结果: " + mathResult); // 输出:数学相加结果: 80
// 情况二:将两个数字转为字符串后再相加,触发字符串拼接
let stringResult = x.toString() + y.toString();
console.log("字符串拼接结果: " + stringResult); // 输出:字符串拼接结果: 5030
这个差异提醒我们:在 JavaScript 中,+ 运算符只要有一侧是字符串,另一侧也会被隐式转换为字符串然后拼接。显式调用 toString() 能让这个意图更明确,代码可读性也会更好。
示例 3:进制转换的实战应用
radix 参数的存在让 toString() 的用途扩展到了进制转换领域。以下是同一个数字在不同基数下的输出。
let decimalValue = 12;
// 转换为二进制字符串
console.log(decimalValue.toString(2)); // 输出:1100
// 转换为八进制字符串
console.log(decimalValue.toString(8)); // 输出:14
// 转换为十六进制字符串
console.log(decimalValue.toString(16)); // 输出:c
进制转换对照说明:
-
二进制 (radix = 2):
12的二进制表示为1100(1×2³ + 1×2² + 0×2¹ + 0×2⁰ = 8 + 4 + 0 + 0 = 12)。 -
八进制 (radix = 8):
12的八进制表示为14(1×8¹ + 4×8⁰ = 8 + 4 = 12)。 -
十六进制 (radix = 16):
12的十六进制表示为c,其中a代表 10,b代表 11,c代表 12。
示例 4:处理较大数字的进制转换
当数字较大时,转换结果也会相应变长。这里用一个稍大的数字 255 来演示。
let colorChannel = 255;
console.log(colorChannel.toString(2)); // 输出:11111111 (8 位全 1,二进制较大值)
console.log(colorChannel.toString(8)); // 输出:377
console.log(colorChannel.toString(16)); // 输出:ff
255 转十六进制得到 "ff",这正是 CSS 颜色值中两个十六进制字符能表示的较大值。如果你在做颜色选择器或者图像处理相关的功能,这个转换会频繁用到。
示例 5:浮点数的进制转换限制
需要特别指出的是,toString(radix) 对于浮点数(带小数的数字)的进制转换支持并不完整。传入非 10 的基数时,小数部分会被直接忽略,只转换整数部分。
let floatNum = 12.75;
console.log(floatNum.toString(2)); // 输出:1100 (小数部分 .75 被忽略)
console.log(floatNum.toString(16)); // 输出:c (同样只转换了整数 12)
如果你需要精确转换浮点数到其他进制,toString() 方法无法直接满足需求,需要自己编写算法或者借助第三方数值处理库。
字面量调用 toString() 的语法注意点
直接对数字字面量调用 toString() 时,有一个语法细节容易被忽略。
// 错误写法:JavaScript 解析器会把第一个点当作小数点
// 10.toString(2); // SyntaxError
// 正确写法一:使用括号包裹数字
console.log((10).toString(2)); // 输出:1010
// 正确写法二:使用两个点(第一个是小数点,第二个是方法调用符)
console.log(10..toString(2)); // 输出:1010
// 正确写法三:先把数字赋值给变量再调用
let num = 10;
console.log(num.toString(2)); // 输出:1010
这个问题的根源在于 JavaScript 的词法解析规则。解析器看到 10. 时会认为这是一个浮点数字面量的开始,而不是整数后跟一个方法调用点。使用括号或双点可以明确告诉解析器你的意图。
toString() 与 String() 函数的区别
很多开发者习惯用 String(num) 来转换数字为字符串,这和 num.toString() 在多数情况下结果相同,但存在两个关键差异:
| 对比维度 | num.toString() | String(num) |
|---|---|---|
| 进制参数 | 支持传入 radix 进行进制转换 | 不支持,按十进制转换 |
| 空值处理 | null 或 undefined 上调用会报错 |
String(null) 返回 "null",安全 |
如果你只需要简单的十进制转字符串,并且不确定变量是否可能为 null,用 String() 更稳妥。如果你需要进制转换功能,toString(radix) 是唯一的选择。
本节课程知识要点
-
类型转换:
toString()将数字对象转换为字符串类型,支持正数、负数和小数。 -
进制参数:通过
radix参数(2 到 36)可将数字按指定进制输出,常用于二进制、八进制、十六进制转换。 -
浮点数限制:传入非 10 基数时,浮点数的小数部分会被忽略,只转换整数部分。
-
语法:对数字字面量直接调用时需使用括号包裹或双点语法,否则会触发语法错误。
-
加法运算影响:数字转字符串后,
+运算符的行为会从数学加法变为字符串拼接。 -
返回值类型:始终返回字符串,原数字对象的值不会被修改。