JavaScript 从入门到精通

第1章 1.4 数据类型与类型转换


🎯 开场 3 分钟:为什么要学这个?

上一章我们学会了变量和作用域,小明现在能声明变量、搞清楚 letconst 的区别了。但有个大问题他还没解决——

他的购物清单程序报错了。

let price = "20";  // 用户输入的价格
let quantity = 5;
let total = price + quantity;

console.log("总价是:" + total);
// 输出:总价是:205

小明懵了:明明 20 + 5 = 25,为什么会输出 205

这就是数据类型在作怪。JavaScript 里 "20" 是字符串,不是数字,所以 + 变成了字符串拼接,而不是数学加法。

学完这一章,你会:
- 搞清楚 JavaScript 有哪几种数据类型
- 知道怎么把 "20" 变成 20 做计算
- 避免像 ===\n\n![Simple tech illustration expla](https://blog.xxyye.com/wp-content/uploads/2026/06/123ad6464dbc723.png)\n\n![AI comic creation scene, creat](https://blog.xxyye.com/wp-content/uploads/2026/06/a0996157dd2bd58.png)\n\n== 这种让人抓狂的坑
- 能写出一个真正能算账的购物清单程序


🧱 基础 25 分钟:核心概念

1. JavaScript 的 8 种数据类型

JavaScript 的数据类型分两类:原始类型(7种)和对象类型(1种)。

想象一下:

原始类型就像散装零食——每包都是独立包装,打开就用,用完就没了。
对象类型就像礼盒套装——里面可以装很多东西,而且礼盒本身还在。

原始类型(7种)
类型 说明 举个例子
string 字符串,一串文本 "hello"
number 数字,整数或小数 42, 3.14
boolean 布尔值,真或假 true, false
undefined 声明了但没赋值 let x;
null 故意设为空 let x = null;
bigint 超级大的整数 9007199254740991n
symbol 独一无二的标识符 Symbol("id")
对象类型(1种)
类型 说明 举个例子
object 对象,可以存键值对 {name: "小明", age: 18}

2. 怎么知道一个值是什么类型?—— typeof

typeof "hello"    // "string"
typeof 42         // "number"
typeof true       // "boolean"
typeof undefined  // "undefined"
typeof null       // "object"  ⚠️ 这是个历史bug
typeof {}         // "object"
typeof []         // "object"  ⚠️ 数组居然也是object

注意一个经典坑:

// 数组用 typeof 居然是 "object"!
typeof [1, 2, 3]  // "object"

想知道是不是数组,要用 Array.isArray()

Array.isArray([1, 2, 3])  // true

3. 字符串(String)——文字信息

生活类比: 字符串就像贴在箱子上的标签,上面写啥就是啥,原封不动。

let name = "小明";
let greeting = "你好," + name + "!";

console.log(greeting);  // 你好,小明!

字符串的常用操作:

let text = "JavaScript";

// 获取长度
text.length  // 10

// 查找子串位置
text.indexOf("Script")  // 4

// 截取子串
text.slice(0, 4)  // "Java"

// 转大小写
text.toUpperCase()  // "JAVASCRIPT"
text.toLowerCase()  // "javascript"

// 是否包含某子串
text.includes("Java")  // true

4. 数字(Number)——数学计算

let price = 19.9;
let tax = 1.1;  // 含税价格倍数

// 数学运算
let total = price * tax;
console.log(total);  // 21.89

常用数字方法:

// 四舍五入
Math.round(3.7)   // 4

// 保留小数位
(3.14159).toFixed(2)  // "3.14"  注意:返回字符串!

// 取最大值最小值
Math.max(1, 5, 3)  // 5
Math.min(1, 5, 3)  // 1

// 随机数
Math.random()  // 0.0 ~ 0.999...

5. 布尔值(Boolean)——真或假

生活类比: 布尔值就像电灯开关,只有两种状态:开(true)或关(false)。

let isStudent = true;
let isLoggedIn = false;

// 逻辑运算
true && false   // false(且)
true || false   // true(或)
!true           // false(非)

哪些值是「假」的?(falsy 值)
- false
- 0
- ""(空字符串)
- null
- undefined
- NaN

除了这些,其他都是「真」:

if ("hello") {
console.log("这段会执行,因为 'hello' 是真");
}

if (0) {
console.log("这段不会执行,因为 0 是假");
}

6. null 和 undefined——空的不同含义

这两个很容易搞混:

含义 什么时候出现
undefined 没赋值 变量声明了但没给值
null 故意为空 开发者主动设置为空
let a;           // a 是 undefined,还没赋值
let b = null;    // b 是 null,我故意写成空的

配图说明:undefined vs null 的区别


7. 数组(Array)——数据的列表

生活类比: 数组就像一排储物柜,每个柜子有编号(索引),从 0 开始。

// 购物清单
let cart = ["牛奶", "面包", "鸡蛋"];

// 按索引访问
cart[0]   // "牛奶"
cart[2]   // "鸡蛋"

// 添加元素
cart.push("饼干");        // 末尾添加
cart.unshift("水");      // 开头添加

// 删除元素
cart.pop();              // 末尾删除
cart.shift();            // 开头删除

// 遍历数组
for (let item of cart) {
console.log(item);
}

8. 对象(Object)——键值对容器

生活类比: 对象就像带标签的文件夹,每个标签(键)对应内容(值)。

let product = {
name: "笔记本电脑",
price: 5999,
inStock: true
};

// 访问属性
product.name        // "笔记本电脑"
product["price"]    // 5999

// 添加/修改属性
product.color = "银色";
product.price = 5499;  // 改价格

// 删除属性
delete product.inStock;

9. 类型转换——字符串 ↔ 数字 ↔ 布尔

这是最重要的部分!小明购物清单报错的原因就在这里。

字符串转数字
let price = "20";
let quantity = "5";

// 方法1:Number()
Number(price) + Number(quantity)  // 25

// 方法2:parseInt() / parseFloat()
parseInt("20px")    // 20,遇到非数字就停
parseFloat("3.14元")  // 3.14

// 方法3:隐式转换(用 + 号)
+ "20" + +"5"       // 25
数字转字符串
let age = 25;

// 方法1:String()
String(25)   // "25"

// 方法2:toString()
(25).toString()  // "25"

// 方法3:隐式转换(拼接空字符串)
age + ""          // "25"
布尔转数字
Number(true)   // 1
Number(false)  // 0
任意转布尔
Boolean(1)        // true
Boolean(0)        // false
Boolean("")       // false
Boolean("hello")  // true
Boolean(null)     // false
Boolean(undefined)// false

10. == 和 === 的区别——最常见的坑

这是 JavaScript 新手最常踩的坑,没有之一。

运算符 名称 行为
== 相等(宽松) 只比较,会自动转换类型
=== 全等(严格) 比较值和类型,都不转换
// == 会自动转换类型,容易出问题
0 == ""      // true(空字符串转成0了)
0 == false   // true(false转成0了)
"5" == 5     // true(字符串转成数字了)

// === 更安全,推荐永远用这个
0 === ""     // false(类型不同)
0 === false  // false(类型不同)
"5" === 5    // false(类型不同)

配图说明:== vs === 的区别

记住: 永远用 ===,除非你有特殊理由要用 ==


🔥 实战 35 分钟:3 个递进的小项目

项目 1(5 分钟):购物小票计算器

场景: 小明在便利店买了东西,要算总价。

// 购物小票计算器
let items = [
{ name: "牛奶", price: 5.5, quantity: 2 },
{ name: "面包", price: 3.0, quantity: 1 },
{ name: "鸡蛋", price: 8.8, quantity: 1 }
];

let total = 0;

for (let item of items) {
// 把 price 和 quantity 转成数字再计算
let itemTotal = Number(item.price) * Number(item.quantity);
total = total + itemTotal;

console.log(item.name + ":¥" + itemTotal.toFixed(2));
}

console.log("-----------");
console.log("总计:¥" + total.toFixed(2));

预期输出:

牛奶:¥11.00
面包:¥3.00
鸡蛋:¥8.80
-----------
总计:¥22.80

一句话解释:Number() 确保价格和数量是数字类型,避免字符串拼接。


项目 2(15 分钟):用户注册信息验证

场景: 验证用户输入的注册信息,格式不对要提示。

// 用户注册信息验证
let formData = {
username: "xiaoming_2024",
age: "18",
email: "xiaoming@example.com",
phone: "13800138000"
};

// 验证函数
function validate(data) {
let errors = [];

// 用户名:字母数字下划线,3-12位
if (!/^\w{3,12}$/.test(data.username)) {
    errors.push("用户名必须是3-12位字母、数字或下划线");
}

// 年龄:必须是正整数
let ageNum = Number(data.age);
if (isNaN(ageNum) || ageNum < 0 || ageNum !== Math.floor(ageNum)) {
    errors.push("年龄必须是正整数");
}

// 邮箱:简单验证
if (!/^[\w.]+@[\w.]+\.\w+$/.test(data.email)) {
    errors.push("邮箱格式不正确");
}

// 手机号:11位数字
if (!/^\d{11}$/.test(data.phone)) {
    errors.push("手机号必须是11位数字");
}

return errors;
}

let errors = validate(formData);

if (errors.length === 0) {
console.log("✅ 注册信息验证通过!");
} else {
console.log("❌ 验证失败:");
for (let err of errors) {
    console.log("  - " + err);
}
}

预期输出:

✅ 注册信息验证通过!

一句话解释:Number() 把字符串转数字,用 isNaN() 检查是不是有效数字。


项目 3(15 分钟):数据清洗工具

场景: 从 CSV 格式的文本中提取数据并计算。

// CSV 数据清洗工具
let rawData = `姓名,数学,语文,英语
小明,85,92,78
小红,90,88,95
小刚,72,85,80`;

function parseCSV(csvText) {
// 按行分割
let lines = csvText.trim().split("\n");

// 第一行是表头
let headers = lines[0].split(",");

// 存放结果
let students = [];

// 逐行解析
for (let i = 1; i < lines.length; i++) {
    let values = lines[i].split(",");
    let student = {
        name: values[0],
        math: Number(values[1]),
        chinese: Number(values[2]),
        english: Number(values[3])
    };
    // 计算总分
    student.total = student.math + student.chinese + student.english;
    students.push(student);
}

return students;
}

function printReport(students) {
console.log("📊 学生成绩报告\n");
console.log("姓名    数学  语文  英语  总分");
console.log("--------------------------------");

for (let s of students) {
    console.log(
        s.name.padEnd(6) + 
        String(s.math).padStart(4) + "  " +
        String(s.chinese).padStart(4) + "  " +
        String(s.english).padStart(4) + "  " +
        String(s.total).padStart(4)
    );
}

// 计算平均分
let avgMath = students.reduce((sum, s) => sum + s.math, 0) / students.length;
console.log("--------------------------------");
console.log("数学平均分:" + avgMath.toFixed(1));
}

let students = parseCSV(rawData);
printReport(students);

预期输出:

📊 学生成绩报告

姓名    数学  语文  英语  总分
--------------------------------
小明      85    92    78   255
小红      90    88    95   273
小刚      72    85    80   237
--------------------------------
数学平均分:82.3

一句话解释:Number() 把 CSV 里的字符串转成数字,才能做数学运算。


💪 进阶 20 分钟:常见坑 + 性能小贴士

坑 1:隐式类型转换的陷阱

// ❌ 错误:字符串拼接优先
console.log("5" + 3);   // "53"(变成字符串拼接了!)

// ✅ 正确:先把字符串转数字
console.log(Number("5") + 3);  // 8

// ✅ 或者用 + 强制转数字
console.log(+ "5" + 3);  // 8

坑 2:parseInt 遇到字母就傻眼了

// ❌ 错误:parseInt 会截断
parseInt("100px");   // 100,后面的 px 被忽略了

// ✅ 正确:用 Number 或正则提取
Number("100px");     // NaN(这不是我想要的)
parseInt("100px", 10); // 100(明确十进制)

// 更好的方法:正则提取数字
parseInt("价格100元", 10);  // NaN
+"100px"  // NaN
Number("100".match(/\d+/)[0])  // 100

坑 3:null 不是 "null" 字符串

let a = null;

console.log(a === "null");  // false!null 是空,不是字符串 "null"
console.log(a === null);    // true

坑 4:数组的 typeof 是 object

// ❌ 错误:以为能这样判断数组
if (typeof arr === "array") { }  // 永远不会成立

// ✅ 正确:用 Array.isArray
if (Array.isArray(arr)) { }

坑 5:浮点数计算的精度问题

// ❌ 错误:0.1 + 0.2 不是精确的 0.3
console.log(0.1 + 0.2 === 0.3);  // false!
console.log(0.1 + 0.2);          // 0.30000000000000004

// ✅ 正确:转为整数计算
let x = 0.1, y = 0.2;
console.log(Math.round((x + y) * 100) / 100);  // 0.3

性能小贴士:避免不必要的类型转换

// ❌ 低效:频繁转换
for (let i = 0; i < 1000; i++) {
let num = Number(strArr[i]);
sum += num;
}

// ✅ 高效:一次性转换
let numArr = strArr.map(Number);
for (let num of numArr) {
sum += num;
}

调试技巧:用 console.log 打印中间值

let price = "20";
let quantity = 5;

console.log("price 类型:", typeof price, "值:", price);
console.log("quantity 类型:", typeof quantity, "值:", quantity);

let total = Number(price) + Number(quantity);
console.log("total 类型:", typeof total, "值:", total);

✏️ 练习题 + 作业题

练习题(5道,10分钟内完成)

练习 1(1分钟):类型判断
- 输入:typeof "hello"typeof 42
- 预期输出:stringnumber
- 提示:用 typeof 运算符

练习 2(2分钟):字符串转数字
- 输入:"25""3.14"
- 预期输出:253.14(数字类型)
- 提示:用 Number()parseFloat()

练习 3(2分钟):修复购物计算

let total = "10" + 5;  // 当前输出 "105"
  • 预期输出:15
  • 提示:把字符串转成数字再相加

练习 4(2分钟):判断数组

let arr = [1, 2, 3];
// 用什么方法判断 arr 是数组?
  • 预期输出:true
  • 提示:Array.isArray() 而不是 typeof

练习 5(3分钟):找出错误

let result = "5" == 5;
console.log(result === true);  // 期望输出 true
  • 问题:为什么输出 false?怎么改?
  • 提示:比较 ===== 的区别

作业题(30分钟-2小时)

作业:做一个「数据类型转换工具箱」

需求描述:
做一个命令行工具,能把用户输入的各种数据转换成目标类型,并显示转换前后的类型。

功能点:
1. 输入一个值,自动显示其类型
2. 能把字符串转成:数字(整数)、数字(浮点)、布尔
3. 能把数字转成:字符串、布尔
4. 能把布尔转成:数字、字符串
5. 如果转换失败(比如 "abc" 转数字),显示 NaN 并提示

加分项:
1. 支持批量转换(一次输入多行)
2. 把结果导出成 JSON 格式

验收标准:
- 能跑起来
- 每种转换都有正确输出
- 代码有适当注释

提交方式: 评论区贴代码或 GitHub 链接


📚 总结 + 资源

3句话总结:
- JavaScript 有 8 种数据类型,7 种原始类型 + 1 种对象类型
- 类型转换用 Number()String()Boolean(),判断类型用 typeof
- 永远用 ===,不用 ==,避免隐式类型转换的坑

延伸学习资源:
1. MDN JavaScript 文档 - 数据类型:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_types
2. 《JavaScript 高级程序设计》第4章 - 变量、作用域与内存
3. 视频:JavaScript 类型转换详解(B站搜索)

互动钩子:
你在写代码时遇到过 NaN 或者 ===== 的坑吗?评论区聊聊你是怎么踩坑和填坑的,老粉优先回复!


下章预告:
现在你学会了数据类型,下一章我们要用它来做一个更实用的东西——模板字符串。想象一下,不用再一层层 + 拼接字符串,而是像填空题一样直接往里面填数据。敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。