JavaScript 数组与对象方法完全指南:从基础到项目实践
JavaScript 中的数组和对象是开发中最常用的数据结构,掌握它们的方法对于高效编程至关重要。本文将深入解析各种数组和对象方法,提供详细的概念解释、参数说明和实用代码示例,并按照功能进行分组展示。
一、数组方法详解
1. 增删元素方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
|---|
| push | 在数组末尾添加一个或多个元素 | ...items:要添加的元素 | 数组新长度 | ✅ |
| pop | 删除数组最后一个元素 | 无 | 被删除的元素 | ✅ |
| unshift | 在数组开头添加一个或多个元素 | ...items:要添加的元素 | 数组新长度 | ✅ |
| shift | 删除数组第一个元素 | 无 | 被删除的元素 | ✅ |
| splice | 在指定位置添加/删除元素 | start(支持负数), deleteCount, ...items | 被删除元素组成的数组 | ✅ |
const fruits = ['apple', 'banana'];
fruits.push('orange');
fruits.unshift('kiwi');
fruits.pop();
fruits.shift();
fruits.splice(1, 0, 'mango', 'grape');
fruits.splice(2, 1);
fruits.splice(1,1,'orange');
2. 查找与访问方法
| 方法 | 概念解释 | 参数说明 | 返回值 |
|---|
| indexOf | 返回元素第一次出现的索引 | searchElement, fromIndex? | 索引值或-1 |
| lastIndexOf | 返回元素最后一次出现的索引 | searchElement, fromIndex? | 索引值或-1 |
| includes | 检查数组是否包含某元素 | searchElement, fromIndex? | Boolean |
| find | 返回满足条件的第一个元素 | callback(element, index, array) | 找到的元素或undefined |
| findIndex | 返回满足条件的第一个元素的索引 | callback(element, index, array) | 索引值或-1 |
| at | 返回指定索引的元素 | index (支持负数) | 元素或undefined |
const numbers = [5, 12, 8,12, 130, 44];
numbers.indexOf(12);
numbers.lastIndexOf(12);
numbers.includes(130);
const found = numbers.find(num => num > 10);
const foundIndex = numbers.findIndex(num => num > 100);
numbers.at(1);
numbers.at(-1);
3. 迭代与转换方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
|---|
| forEach | 对每个元素执行函数 | callback(element, index, array) | undefined | ❌ |
| map | 创建包含回调结果的新数组 | callback(element, index, array) | 新数组 | ❌ |
| filter | 创建包含通过测试的元素的新数组 | callback(element, index, array) | 新数组 | ❌ |
| reduce | 从左到右执行reducer函数 | callback(accumulator, currentValue, index, array), initialValue? | 累积值 | ❌ |
| reduceRight | 从右到左执行reducer函数 | 同reduce | 累积值 | ❌ |
| flat | 将嵌套数组扁平化 | depth?(默认1) | 新数组 | ❌ |
| flatMap | 先map后扁平化 | callback(element, index, array) | 新数组 | ❌ |
const numbers = [1, 2, 3, 4];
numbers.forEach(num => console.log(num * 2));
const doubled = numbers.map(num => num * 2);
const evens = numbers.filter(num => num % 2 === 0);
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
const nested = [1, [2, 3], [4, [5]]];
nested.flat();
nested.flat(2);
const phrases = ["hello world", "goodbye moon"];
const words = phrases.flatMap(phrase => phrase.split(" "));
4. 排序与操作方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
|---|
| sort | 对数组元素进行排序 | compareFunction(a, b)? | 排序后的数组 | ✅ |
| reverse | 反转数组元素顺序 | 无 | 反转后的数组 | ✅ |
| slice | 返回数组的一部分浅拷贝 | start?, end? :支持负数 | 新数组 | ❌ |
| concat | 合并两个或多个数组 | ...arraysOrValues:数组或值 | 新数组 | ❌ |
| join | 将数组元素连接为字符串 | separator?(默认逗号) | 字符串 | ❌ |
const fruits = ['banana', 'apple', 'cherry'];
fruits.sort();
const numbers = [40, 100, 1, 5, 25];
numbers.sort((a, b) => a - b);
numbers.sort((a, b) => b - a);
fruits.reverse();
const sliced = fruits.slice(1, 3);
const sliced1 = fruits.slice(1);
const sliced2 = fruits.slice(-1);
const moreFruits = fruits.concat(['orange', 'kiwi']);
const moreFruits1 = fruits.concat(‘mengo’);
fruits.join(' and ');
5. 其他实用方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
|---|
| every | 检查所有元素是否通过测试 | callback(element, index, array) | Boolean | ❌ |
| some | 检查至少一个元素通过测试 | callback(element, index, array) | Boolean | ❌ |
| fill | 用静态值填充数组 | value, start?, end? | 修改后的数组 | ✅ |
| copyWithin | 复制数组元素到同一数组的不同位置 | target, start?, end? | 修改后的数组 | ✅ |
| Array.isArray | 检查是否为数组 | value | Boolean | ❌ |
const ages = [32, 33, 16, 40];
ages.every(age => age > 18);
ages.some(age => age > 18);
const emptyArray = new Array(3);
emptyArray.fill('default');
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3, 5);
Array.isArray(arr);
Array.isArray({});
二、对象方法详解
1. 基本操作方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否修改原对象 |
|---|
| Object.assign | 复制属性到目标对象 | target, ...sources | 目标对象 | ✅ |
| Object.keys | 返回对象自身可枚举属性键数组 | obj | 属性键数组 | ❌ |
| Object.values | 返回对象自身可枚举属性值数组 | obj | 属性值数组 | ❌ |
| Object.entries | 返回[key, value]数组 | obj | [key, value]数组 | ❌ |
| Object.hasOwn | 检查对象是否有指定属性 | (obj, prop) | Boolean | ❌ |
| Object.freeze | 冻结对象(不可修改) | obj | 冻结的对象 | ✅ |
| Object.seal | 密封对象(不可添加/删除属性) | obj | 密封的对象 | ✅ |
const person = { name: 'Alice', age: 30 };
const job = { title: 'Developer' };
const merged = Object.assign({}, person, job);
Object.keys(person);
Object.values(person);
Object.entries(person);
Object.hasOwn(person,'name');
Object.freeze(person);
person.age = 31;
Object.seal(person);
person.location = 'Paris';
delete person.name;
2. 属性描述与原型方法
| 方法 | 概念解释 | 参数说明 | 返回值 | 是否修改原对象 |
|---|
| Object.defineProperty | 定义/修改对象属性 | obj, prop, descriptor | 修改后的对象 | ✅ |
| Object.defineProperties | 定义/修改多个对象属性 | obj, props | 修改后的对象 | ✅ |
| Object.getOwnPropertyDescriptor | 获取属性描述符 | obj, prop | 属性描述符对象 | ❌ |
| Object.getPrototypeOf | 获取对象的原型 | obj | 原型对象或null | ❌ |
| Object.setPrototypeOf | 设置对象的原型 | obj, prototype | 设置后的对象 | ✅ |
| Object.create | 使用指定原型创建新对象 | proto, propertiesObject? | 新对象 | ❌ |
const obj = {};
Object.defineProperty(obj, 'id', {
value: 1,
writable: false,
enumerable: true,
configurable: false
});
const descriptor = Object.getOwnPropertyDescriptor(obj, 'id');
const parent = { greet() { return 'Hello'; } };
const child = Object.create(parent);
Object.getPrototypeOf(child) === parent;
const newProto = { bye() { return 'Goodbye'; } };
Object.setPrototypeOf(child, newProto);
child.bye();
3. 其他实用方法
| 方法 | 概念解释 | 参数说明 | 返回值 |
|---|
| Object.is | 比较两个值是否相同 | value1, value2 | Boolean |
| Object.fromEntries | 将键值对列表转为对象 | iterable | 新对象 |
| Object.isPrototypeOf() | 检查对象是否在原型链中 | obj: 要检查的对象 | Boolean |
| Object.hasOwn | 检查对象是否具有指定属性(自身属性) | obj, prop | Boolean |
| Object.preventExtensions | 防止对象扩展(不能添加新属性) | obj | 不可扩展的对象 |
| Object.groupBy() | 按条件分组对象数组 | (items, callback) | 分组后的对象 |
| structuredClone() | 深拷贝对象 | obj: 要拷贝的对象 | 新对象 |
Object.is(NaN, NaN);
Object.is(0, -0);
const entries = [['name', 'Bob'], ['age', 25]];
const newObj = Object.fromEntries(entries);
Array.prototype.isPrototypeOf([]);
Object.hasOwn(newObj, 'name');
Object.hasOwn(newObj, 'toString');
Object.preventExtensions(newObj);
newObj.location = 'London';
const inventory = [
{ name: 'asparagus', type: 'vegetables' },
{ name: 'bananas', type: 'fruit' },
{ name: 'goat', type: 'meat' }
];
const grouped = Object.groupBy(inventory, ({ type }) => type);
const original = { a: 1, b: { c: 2 } };
const arr = [1,2,[3,4,[55]]];
const copy = structuredClone(original);
const copyArr = structuredClone(arr);
三、最佳实践与性能优化
1. 数组操作黄金法则
方法选择指南:
- 增删元素:
push()/pop()/splice()
- 查询转换:
slice()/concat()/join()
- 迭代处理:
- 简单遍历 →
forEach()
- 转换元素 →
map()
- 筛选元素 →
filter()
- 聚合计算 →
reduce()
- 查找元素 →
find()/findIndex()
- 排序操作:
sort()/reverse()
- ES6+新特性:
flat()/flatMap()/includes()
性能陷阱:
const results = data.map(item => {
return processItem(item);
});
function process(item) { }
const results = data.map(process);
const filtered = array.filter(x => x > 10);
const result = filtered.map(x => x * 2);
const result = array.reduce((acc, x) => {
if (x > 10) acc.push(x * 2);
return acc;
}, []);
const largeData = new Float64Array(1000000);
2. 对象操作专业建议
方法选择指南:
- 属性操作:
Object.keys()/values()/entries()
- 对象创建:
Object.create()/Object.fromEntries()
- 属性控制:
Object.defineProperty()/defineProperties()
- 不可变性:
Object.freeze()/seal()/preventExtensions()
- 原型操作:
Object.getPrototypeOf()/setPrototypeOf()
- ES6+新特性:
Object.groupBy()/hasOwn()/structuredClone()
设计模式:
function createUser(name) {
return Object.assign(Object.create(userProto), {
name,
createdAt: new Date()
});
}
const canEat = { eat() { } };
const canWalk = { walk() { } };
function createPerson(name) {
return Object.assign({ name }, canEat, canWalk);
}
function createObservable(target) {
return new Proxy(target, {
set(obj, prop, value) {
console.log(`Property ${prop} changed`);
obj[prop] = value;
return true;
}
});
}
四、终极对比总结表
数组方法速查表
| 分类 | 方法 | 修改原数组 | 返回值 | 典型应用场景 |
|---|
| 增删元素 | push()/pop() | ✅ | 长度/被删元素 | 栈操作 |
| unshift()/shift() | ✅ | 长度/被删元素 | 队列操作 |
| splice() | ✅ | 被删除元素数组 | 任意位置增删 |
| 查询转换 | concat() | ❌ | 新数组 | 数组合并 |
| slice() | ❌ | 新数组 | 数组切片 |
| join() | ❌ | 字符串 | 数组转字符串 |
| 迭代处理 | forEach() | ❌ | undefined | 简单遍历 |
| map() | ❌ | 新数组 | 数据转换 |
| filter() | ❌ | 新数组 | 数据筛选 |
| reduce() | ❌ | 累计值 | 数据聚合 |
| find()/findIndex() | ❌ | 元素/索引 | 条件查找 |
| 排序查找 | sort()/reverse() | ✅ | 排序后数组 | 数据排序 |
| indexOf()/includes() | ❌ | 索引/Boolean | 元素存在性检查 |
| ES6+新特性 | flat()/flatMap() | ❌ | 新数组 | 嵌套数组处理 |
| at() | ❌ | 元素 | 安全索引访问 |
对象方法速查表
| 分类 | 方法 | 修改原对象 | 返回值 | 典型应用场景 |
|---|
| 属性操作 | keys()/values() | ❌ | 数组 | 获取属性名/值列表 |
| entries() | ❌ | [key,value]数组 | 对象转为键值对数组 |
| assign() | ✅ | 目标对象 | 对象合并/浅拷贝 |
| hasOwn() | ❌ | Boolean | 属性存在性检查 |
| 对象创建 | create() | ❌ | 新对象 | 原型继承 |
| fromEntries() | ❌ | 新对象 | 键值对数组转对象 |
| 不可变性 | freeze() | ✅ | 冻结对象 | 创建不可变对象 |
| seal() | ✅ | 密封对象 | 防止新增/删除属性 |
| 原型操作 | getPrototypeOf() | ❌ | 原型对象 | 原型链检查 |
| setPrototypeOf() | ✅ | 修改后对象 | 动态修改原型 |
| 属性控制 | defineProperty() | ✅ | 修改后对象 | 精细控制属性特性 |
| getOwnPropertyDescriptor() | ❌ | 描述符对象 | 获取属性配置 |
| ES6+新特性 | groupBy() | ❌ | 分组对象 | 数据分组统计 |
| structuredClone() | ❌ | 深拷贝对象 | 对象深拷贝 |
五、项目实践应用
1. 数组去重与排序
const numbers = [3, 1, 2, 3, 4, 2, 5, 1];
const unique1 = [...new Set(numbers)].sort((a, b) => a - b);
const unique2 = numbers
.filter((num, index) => numbers.indexOf(num) === index)
.sort((a, b) => b - a);
const unique3 = numbers.reduce((acc, num) => {
if (!acc.includes(num)) acc.push(num);
return acc;
}, []).sort((a, b) => a - b);
console.log(unique1);
console.log(unique2);
console.log(unique3);
2. 对象深度合并
function deepMerge(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
deepMerge(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key]);
}
}
}
return deepMerge(target, ...sources);
}
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}
const defaultConfig = {
api: { baseURL: '/api', timeout: 30000 },
logging: { level: 'info' }
};
const userConfig = {
api: { baseURL: 'https://api.example.com' },
features: { analytics: true }
};
const mergedConfig = deepMerge({}, defaultConfig, userConfig);
3. 数据转换与处理
const apiResponse = [
{ id: 1, name: 'Alice', department: 'HR', salary: 60000 },
{ id: 2, name: 'Bob', department: 'IT', salary: 80000 },
{ id: 3, name: 'Charlie', department: 'IT', salary: 75000 }
];
const itEmployees = apiResponse.filter(emp => emp.department === 'IT');
const totalSalary = itEmployees.reduce((sum, emp) => sum + emp.salary, 0);
const avgSalary = totalSalary / itEmployees.length;
const salaryMap = Object.fromEntries(
itEmployees.map(emp => [emp.name, emp.salary])
);
const sortedEmployees = [...itEmployees].sort((a, b) => b.salary - a.salary);
4. 表单数据处理
function formDataToObject(formElement) {
const formData = new FormData(formElement);
return Object.fromEntries(formData.entries());
}
const form = document.querySelector('#userForm');
const userData = formDataToObject(form);
function validateFormData(data) {
const errors = {};
if (!data.name) errors.name = 'Name is required';
if (!data.email.includes('@')) errors.email = 'Invalid email format';
return Object.keys(errors).length ? errors : null;
}
5. 状态管理
const cartState = {
items: [
{ id: 1, name: 'Laptop', price: 999, quantity: 1 },
{ id: 2, name: 'Mouse', price: 25, quantity: 2 }
],
discount: 0.1
};
function addToCart(item) {
const existingItem = cartState.items.find(i => i.id === item.id);
if (existingItem) {
return {
...cartState,
items: cartState.items.map(i =>
i.id === item.id
? { ...i, quantity: i.quantity + 1 }
: i
)
};
} else {
return {
...cartState,
items: [...cartState.items, { ...item, quantity: 1 }]
};
}
}
function calculateTotal(cart) {
return cart.items.reduce(
(total, item) => total + (item.price * item.quantity), 0
) * (1 - cart.discount);
}
6. 高级数据处理
function deepFreeze(obj) {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj[prop] !== null &&
typeof obj[prop] === 'object' &&
!Object.isFrozen(obj[prop])) {
deepFreeze(obj[prop]);
}
});
return obj;
}
function flattenObject(obj, prefix = '') {
return Object.entries(obj).reduce((acc, [key, value]) => {
const prefixedKey = prefix ? `${prefix}.${key}` : key;
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
Object.assign(acc, flattenObject(value, prefixedKey));
} else {
acc[prefixedKey] = value;
}
return acc;
}, {});
}
const nestedObj = {
user: {
name: 'Alice',
address: {
city: 'Paris',
country: 'France'
}
},
roles: ['admin', 'editor']
};
const flatObj = flattenObject(nestedObj);
总结
掌握 JavaScript 数组和对象的方法是成为高效开发者的关键。本文详细介绍了:
- 数组方法:按功能分组(增删、查找、迭代、排序等)
- 对象方法:基本操作、属性描述、原型方法等
- 项目实践:数据转换、表单处理、状态管理等应用场景
- 最佳实践:性能优化、避免陷阱、现代特性应用
通过理解这些方法的原理和应用场景,结合项目实践中的示例,你将能够编写更简洁、高效和可维护的 JavaScript 代码。记住,选择合适的方法往往比编写复杂逻辑更重要!