Day 6: 数组与对象
🎯 学习目标
- 深入理解数组的操作和常用方法
- 掌握对象的创建、访问和操作
- 学会使用数组和对象的高级特性
- 理解引用类型的工作原理
💡 核心概念
什么是数组?
数组是有序的数据集合,可以存储多个值。想象成一辆火车,每节车厢(索引)装着一个乘客(值)。
// 创建数组
let fruits = ["苹果", "香蕉", "橙子"];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "你好", true, null];
什么是对象?
对象是无序的键值对集合。想象成一个档案柜,每个文件夹(属性)都贴着标签(键)。
// 创建对象
let person = {
name: "张三",
age: 25,
city: "北京"
};
📚 数组详解
1. 创建数组
// 字面量方式(推荐)
let arr1 = [1, 2, 3];
// 构造函数
let arr2 = new Array(1, 2, 3);
// 创建空数组
let arr3 = [];
let arr4 = new Array();
// 创建指定长度的数组
let arr5 = new Array(5); // [empty × 5]
2. 访问和修改数组元素
let colors = ["红", "绿", "蓝"];
// 访问元素(索引从0开始)
console.log(colors[0]); // "红"
console.log(colors[1]); // "绿"
// 修改元素
colors[0] = "橙色";
console.log(colors); // ["橙色", "绿", "蓝"]
// 获取数组长度
console.log(colors.length); // 3
3. 数组常用方法
添加元素
let arr = [1, 2, 3];
// push() - 在末尾添加
arr.push(4); // [1, 2, 3, 4]
arr.push(5, 6); // [1, 2, 3, 4, 5, 6]
// unshift() - 在开头添加
arr.unshift(0); // [0, 1, 2, 3, 4, 5, 6]
// splice() - 在指定位置添加
arr.splice(3, 0, 3.5); // [0, 1, 2, 3.5, 3, 4, 5, 6]
删除元素
let arr = [1, 2, 3, 4, 5];
// pop() - 删除末尾
let last = arr.pop(); // 返回 5, arr = [1, 2, 3, 4]
// shift() - 删除开头
let first = arr.shift(); // 返回 1, arr = [2, 3, 4]
// splice() - 删除指定位置
arr.splice(1, 1); // 删除索引1的1个元素, arr = [2, 4]
查找元素
let fruits = ["苹果", "香蕉", "橙子", "苹果"];
// indexOf() - 查找索引
console.log(fruits.indexOf("香蕉")); // 1
console.log(fruits.indexOf("葡萄")); // -1(未找到)
// lastIndexOf() - 最后一次出现的位置
console.log(fruits.lastIndexOf("苹果")); // 3
// includes() - 是否包含
console.log(fruits.includes("橙子")); // true
console.log(fruits.includes("葡萄")); // false
// find() - 查找符合条件的元素
let numbers = [1, 2, 3, 4, 5];
let found = numbers.find(num => num > 3); // 4
// findIndex() - 查找符合条件的索引
let index = numbers.findIndex(num => num > 3); // 3
遍历数组
let numbers = [1, 2, 3, 4, 5];
// forEach() - 遍历每个元素
numbers.forEach((num, index) => {
console.log(`索引${index}: ${num}`);
});
// map() - 转换数组,返回新数组
let doubled = numbers.map(num => num * 2); // [2, 4, 6, 8, 10]
// filter() - 过滤数组,返回新数组
let evens = numbers.filter(num => num % 2 === 0); // [2, 4]
// reduce() - 累计计算
let sum = numbers.reduce((total, num) => total + num, 0); // 15
// some() - 是否有符合条件的元素
let hasEven = numbers.some(num => num % 2 === 0); // true
// every() - 是否所有元素都符合条件
let allPositive = numbers.every(num => num > 0); // true
排序
let arr = [3, 1, 4, 1, 5, 9];
// sort() - 排序(默认按字符串排序)
arr.sort(); // [1, 1, 3, 4, 5, 9]
// 数字排序
arr.sort((a, b) => a - b); // 升序
arr.sort((a, b) => b - a); // 降序
// reverse() - 反转
arr.reverse(); // [9, 5, 4, 3, 1, 1]
其他方法
// join() - 转为字符串
let arr = [1, 2, 3];
console.log(arr.join("-")); // "1-2-3"
console.log(arr.join()); // "1,2,3"
// slice() - 截取数组(不修改原数组)
let arr = [1, 2, 3, 4, 5];
let sliced = arr.slice(1, 3); // [2, 3]
// concat() - 合并数组
let arr1 = [1, 2];
let arr2 = [3, 4];
let merged = arr1.concat(arr2); // [1, 2, 3, 4]
// spread(...) - 展开数组
let arr = [1, 2, 3];
let newArr = [...arr, 4, 5]; // [1, 2, 3, 4, 5]
🗂️ 对象详解
1. 创建对象
// 字面量方式(推荐)
let person = {
name: "张三",
age: 25
};
// 构造函数
let obj = new Object();
obj.name = "李四";
obj.age = 30;
// Object.create()
let proto = { greet: function() { return "Hello"; } };
let obj = Object.create(proto);
2. 访问对象属性
let person = {
name: "张三",
age: 25,
"full name": "张 三" // 带空格的属性名
};
// 点表示法
console.log(person.name); // "张三"
// 方括号表示法
console.log(person["age"]); // 25
console.log(person["full name"]); // "张 三"(必须用方括号)
// 动态访问
let key = "name";
console.log(person[key]); // "张三"
3. 添加和修改属性
let person = { name: "张三" };
// 添加属性
person.age = 25;
person.city = "北京";
// 修改属性
person.name = "李四";
// 方括号方式
person["email"] = "test@example.com";
4. 删除属性
let person = {
name: "张三",
age: 25,
city: "北京"
};
delete person.age;
delete person["city"];
console.log(person); // {name: "张三"}
5. 对象方法
let calculator = {
add: function(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
}
};
console.log(calculator.add(5, 3)); // 8
console.log(calculator.subtract(5, 3)); // 2
6. 遍历对象
let person = {
name: "张三",
age: 25,
city: "北京"
};
// for...in 遍历键
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
// Object.keys() 获取所有键
let keys = Object.keys(person); // ["name", "age", "city"]
// Object.values() 获取所有值
let values = Object.values(person); // ["张三", 25, "北京"]
// Object.entries() 获取键值对数组
let entries = Object.entries(person);
// [["name", "张三"], ["age", 25], ["city", "北京"]]
🔄 引用类型
数组和对象是引用类型
// 赋值是引用,不是复制
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4](也被修改了!)
// 对象同理
let obj1 = { name: "张三" };
let obj2 = obj1;
obj2.name = "李四";
console.log(obj1.name); // "李四"
复制数组和对象
// 数组复制
let arr = [1, 2, 3];
let copy1 = arr.slice(); // 方式1
let copy2 = [...arr]; // 方式2(spread)
let copy3 = Array.from(arr); // 方式3
// 对象浅复制
let obj = { name: "张三", age: 25 };
let copy1 = Object.assign({}, obj); // 方式1
let copy2 = { ...obj }; // 方式2(spread)
// 深拷贝(嵌套对象)
let deepObj = {
person: { name: "张三", age: 25 }
};
let deepCopy = JSON.parse(JSON.stringify(deepObj));
🎮 实战示例
示例1:购物车管理
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(product, price, quantity = 1) {
this.items.push({ product, price, quantity });
}
removeItem(index) {
this.items.splice(index, 1);
}
getTotal() {
return this.items.reduce((total, item) => {
return total + item.price * item.quantity;
}, 0);
}
getReceipt() {
return this.items.map(item =>
`${item.product}: ¥${item.price} × ${item.quantity}`
).join('\n');
}
}
// 使用
let cart = new ShoppingCart();
cart.addItem("苹果", 5.5, 2);
cart.addItem("香蕉", 3.0, 3);
console.log(cart.getReceipt());
console.log(`总计: ¥${cart.getTotal()}`);
示例2:学生成绩管理
let students = [
{ id: 1, name: "张三", scores: { math: 90, english: 85 } },
{ id: 2, name: "李四", scores: { math: 78, english: 92 } },
{ id: 3, name: "王五", scores: { math: 88, english: 76 } }
];
// 找出数学平均分
let avgMath = students.reduce((sum, student) =>
sum + student.scores.math, 0
) / students.length;
// 找出英语最高分的学生
let topEnglish = students.reduce((top, student) =>
student.scores.english > top.scores.english ? student : top
);
// 筛选数学及格的学生
let mathPassed = students.filter(s => s.scores.math >= 80);
示例3:待办事项应用
class TodoApp {
constructor() {
this.todos = [];
}
add(title) {
this.todos.push({
id: Date.now(),
title: title,
completed: false,
createdAt: new Date()
});
}
toggle(id) {
let todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
}
delete(id) {
this.todos = this.todos.filter(t => t.id !== id);
}
list(filter = 'all') {
switch (filter) {
case 'active':
return this.todos.filter(t => !t.completed);
case 'completed':
return this.todos.filter(t => t.completed);
default:
return this.todos;
}
}
}
✍️ 练习任务
练习1:数组去重
function unique(arr) {
return [...new Set(arr)];
}
// 或使用 filter
function unique2(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
练习2:数组扁平化
function flatten(arr) {
return arr.flat();
}
// 扁平化任意深度
function flattenDeep(arr) {
return arr.flat(Infinity);
}
// 手动实现
function flattenManual(arr) {
let result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result = result.concat(flattenManual(item));
} else {
result.push(item);
}
});
return result;
}
练习3:对象合并
function mergeObjects(...objs) {
return Object.assign({}, ...objs);
}
// 或使用 spread
function mergeObjects2(...objs) {
return { ...objs };
}
🎓 今日挑战
项目:图书管理系统
class Library {
constructor() {
this.books = [
{ id: 1, title: "JavaScript高级程序设计", author: "Nicholas", available: true },
{ id: 2, title: "深入浅出Node.js", author: "朴灵", available: true },
{ id: 3, title: "CSS揭秘", author: "Lea Verou", available: false }
];
this.borrowed = {}; // { userId: [bookIds] }
}
// 添加图书
addBook(title, author) {
let id = this.books.length + 1;
this.books.push({ id, title, author, available: true });
return id;
}
// 借书
borrowBook(userId, bookId) {
let book = this.books.find(b => b.id === bookId);
if (!book || !book.available) {
return false;
}
book.available = false;
if (!this.borrowed[userId]) {
this.borrowed[userId] = [];
}
this.borrowed[userId].push(bookId);
return true;
}
// 还书
returnBook(userId, bookId) {
let book = this.books.find(b => b.id === bookId);
if (!book) return false;
book.available = true;
this.borrowed[userId] = this.borrowed[userId]
.filter(id => id !== bookId);
return true;
}
// 查找图书
searchBooks(keyword) {
return this.books.filter(book =>
book.title.includes(keyword) ||
book.author.includes(keyword)
);
}
// 列出可借图书
listAvailable() {
return this.books.filter(book => book.available);
}
}
💡 最佳实践
1. 使用 const 声明数组
const arr = [1, 2, 3];
arr.push(4); // ✅ 可以修改内容
// arr = []; // ❌ 不能重新赋值
2. 使用解构
// 数组解构
let [first, second, ...rest] = [1, 2, 3, 4, 5];
// 对象解构
let { name, age } = person;
3. 使用可选链
let city = person?.address?.city; // 安全访问
4. 避免直接修改原数组
// ❌ 修改原数组
arr.sort();
// ✅ 创建新数组
let sorted = [...arr].sort();
学习时间: 2026-03-07 16:30
难度: ⭐⭐⭐⭐☆
预计用时: 3-4 小时
关键词: 数组, 对象, 方法, 引用类型
相关标签: #02-变量与数据