一文搞懂 JavaScript 数据类型转换(显式 & 隐式全解析)

1、为什么 JS 会有数据类型转换?

先从一个最本质的特点说起 👇

(1) JavaScript 是一门「动态类型语言」

js 复制代码
var i = 1;
i = "zhangsan";
console.log(i);

在 JS 中:

  • 变量没有固定类型
  • 类型是在运行时才确定的

这和 Java / TypeScript 完全不同。

(2) 运算符「有类型预期」

虽然变量没有类型,但运算符是有要求的 。虽然是两个字符串相减,但是依然得到数值 1,原因就在于 JavaScript 将运算子自动转为了数值。

所以接下来就来看一下 JavaScript 中如何进行数据类型转换。

js 复制代码
'4' - '3' // 1

减法运算符期望的是「数字」,于是 JS 会在背后偷偷做一件事:

js 复制代码
'4' → 4
'3' → 3

这就是数据类型转换存在的根本原因


2、显式转换(你自己动手)

强制转换主要指使用Number()String()Boolean()三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。

2.1 Number():把一切变成数字

(1)原始类型

原始类型值的转换规则如下:

js 复制代码
Number('')        // 0
Number('123')     // 123
Number('zhangsan')  // NaN
Number('123?')    // NaN

Number(true)      // 1
Number(false)     // 0

Number(undefined) // NaN
Number(null)      // 0

⚠️ 注意:Number() 非常严格parseInt能转多少转多少,Number不纯就直接 NaN

js 复制代码
parseInt('123abc') // 123
Number('123abc')   // NaN

(2)对象转换规则(重点)

简单的规则是,Number方法的参数是对象时,将返回NaN,除非是包含单个数值的数组。

js 复制代码
Number({n: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([6]) // 6

内部其实走了三步规则

  1. 先调用对象自身的 valueOf()方法。如果返回原始类型的值,则直接对该值使用Number函数,不在进行后续操作。
  2. 如果valueOf方法返回的还是对象,则改为调用对象的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续操作。
  3. 如果toString方法返回的仍是对象,就报错。
js 复制代码
var obj = { name: 'zhangsan' };
obj.valueOf();   // { name: 'zhangsan' }
obj.toString();  // "[object Object]"
Number(obj);     // NaN

// 等价于
if(typeof obj.valueOf() === 'object') {
   Number(obj.toString());
} else {
   Number(obj.valueOf());
}

上述代码,Number函数将obj对象转为数值,首先调用obj.valueOf方法, 结果返回对象本身;于是,继续调用obj.toString方法,这时返回字符串[object Object],对这个字符串使用Number函数,得到NaN

如果toString方法返回的仍不是原始类型的值,结果就会报错

js 复制代码
const obj = {
  valueOf() {
    return {}
  },
  toString() {
    return {}
  }
}
Number(obj);
// TypeError: Cannot convert object to primitive value

从上述可以看出,valueOftoString方法,是可以自定义的。

js 复制代码
// 验证会调用valueOf
const obj = {
  valueOf() {
    return 10;
  }
}
Number(obj); // 10

// 验证会调用toString
const obj2 = {
  toString() {
    return 20
  }
}
Number(obj2); // 20

// 验证valueOf方法先于toString方法
const obj3 = {
  valueOf() {
    return 10
  },
  toString() {
    return 20
  }
}
Number(obj3); // 10

数组为什么不一样?

js 复制代码
Number([5])    // 5
Number([1,2])  // NaN

原因拆解:

js 复制代码
[5].valueOf()  // [5]
[5].toString()   // "5"
Number("5")      // 5

[1,2].toString() // "1,2"
Number("1,2")    // NaN

执行顺序永远是:

valueOf方法 优先于 toString方法


2.2 String():转成字符串

(1)原始类型值

js 复制代码
String(123);        // "123"
String(true);       // "true"
String('test');     // "test"
String(undefined);  // "undefined"
String(null);       // "null"

对象规则

String方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。

js 复制代码
String({a:1}) // "[object Object]"
String([1,2]) // "1,2"

String方法背后的转换规则,与Number方法基本相同,只是互换了valueOf方法和toString方法的执行顺序。

  1. 先调用自身toString方法,如果返回原始类型的值,则对该值使用String函数,不再进行后续操作。
  2. 如果toString方法返回的还是对象,则调用对象的valueOf方法,如果valueOf方法返回原始类型的值,则对该值使用String函数,不再进行后续操作。
  3. 如果valueOf方法返回的仍是对象,就报错。

例如:

js 复制代码
String({ name:'zhangsan' }); // "[object Object]"
// 等价于
String({ name:'zhangsan' }.toString()) // "[object Object]"

如果toStringvalueOf方法,返回的都是对象就报错。

js 复制代码
const obj = {
  toString() {
    console.log('1');
    return {}
  },

  valueOf() {
    console.log('2');
    return {}
  }
};

String(obj) // TypeError: Cannot convert object to primitxive value

从上述可以看出,toStringvalueOf方法,是可以自定义的。

js 复制代码
const obj = {
  toString() {
    console.log('1');
    // return {}
    return 10;
  },

  valueOf() {
    console.log('2');
    return 20;
  }
};
// toString方法如果返回10则输出'10'
// toString返回如果返回{},则继续执行valueOf方法,输出'20'
String(obj);

2.3 Boolean():最简单,但最容易踩坑

Boolean()函数可以将任意类型的值转为布尔值。它的转换规则比较简单,只有 5 个值是 false ,其他的值全部为true

js 复制代码
false
0
''
null
undefined
NaN
js 复制代码
Boolean({})   // true
Boolean([])   // true
Boolean(false) // false

⚠️ 所有对象的布尔值,永远是 true

4、隐式转换

(1) 自动转布尔(if 判断)

js 复制代码
if ('abc') {
  console.log('Hello');
}

等价于:

js 复制代码
if (Boolean('abc')) {}

快速写法:

js 复制代码
!!'abc' // true

(2)自动转字符串(+ 号)

js 复制代码
'5' + 1        // "51"
'5' + true     // "5true"
'5' + {}       // "5[object Object]"

核心规则:

只要有字符串,+ 就变成拼接


(3)自动转数字(- * /)

js 复制代码
'5' - '2'     // 3
'5' * []      // 0
'5' * [2]     // 10
'5' * [1,2]   // NaN

拆解 [] 的例子:

js 复制代码
[].toString()  // ""
Number("")     // 0

(4)一元运算符 +

js 复制代码
+'abc'   // NaN
+true    // 1
+false   // 0

JavaScript 的类型转换分为 显式转换隐式转换

  • 显式转换 :是开发者主动调用 NumberStringBoolean 等方法;
  • 隐式转换:发生在运算或条件判断中,由 JS 根据上下文自动完成;
  • 转换本质:根据运算符的预期类型,调用对应的转换规则。
相关推荐
阿蒙Amon2 小时前
C#每日面试题-简述命名空间和程序集
java·面试·c#
小宇的天下2 小时前
Virtuoso 中的tech file 详细说明
java·服务器·前端
m0_502724952 小时前
JavaScript - 让一个数组对象重复多次
javascript
怕浪猫2 小时前
React从入门到出门第八章 React19新特性use()/useOptimistic 原理与业务落地
javascript·react.js·前端框架
Zoey的笔记本2 小时前
「软件开发缺陷管理工具」的闭环追踪设计与自动化集成架构
java·服务器·前端
Sapphire~2 小时前
【前端基础】04-XSS(跨站脚本攻击,Cross-Site Scripting)
前端·xss
奔跑的web.2 小时前
Vue 3.6 重磅新特性:Vapor Mode 深度解析
前端·javascript·vue.js
MediaTea2 小时前
Python OOP 设计思想 13:封装服务于演化
linux·服务器·前端·数据库·python
唐璜Taro2 小时前
2026全栈开发AI智能体教程(开篇一)
javascript·langchain