JavaScript 从入门到精通
第1章 1.4 数据类型与类型转换
🎯 开场 3 分钟:为什么要学这个?
上一章我们学会了变量和作用域,小明现在能声明变量、搞清楚 let 和 const 的区别了。但有个大问题他还没解决——
他的购物清单程序报错了。
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\n\n\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
- 预期输出:string 和 number
- 提示:用 typeof 运算符
练习 2(2分钟):字符串转数字
- 输入:"25" 和 "3.14"
- 预期输出:25 和 3.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 或者 == 和 === 的坑吗?评论区聊聊你是怎么踩坑和填坑的,老粉优先回复!
下章预告:
现在你学会了数据类型,下一章我们要用它来做一个更实用的东西——模板字符串。想象一下,不用再一层层 + 拼接字符串,而是像填空题一样直接往里面填数据。敬请期待!

评论(0)