JavaScript 中的数组和对象是开发中最常用的数据结构,掌握它们的方法对于高效编程至关重要,本文将深入解析各种数组和对象方法,提供详细的概念解释、参数说明和实用代码示例,并按照功能进行分组展示,需要的朋友可以参考下
JavaScript 数组与对象方法完全指南:从基础到项目实践
一、数组方法详解
1. 增删元素方法
方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
---|
push | 在数组末尾添加一个或多个元素 | ...items:要添加的元素 | 数组新长度 | ✅ |
pop | 删除数组最后一个元素 | 无 | 被删除的元素 | ✅ |
unshift | 在数组开头添加一个或多个元素 | ...items:要添加的元素 | 数组新长度 | ✅ |
shift | 删除数组第一个元素 | 无 | 被删除的元素 | ✅ |
splice | 在指定位置添加/删除元素 | start(支持负数), deleteCount, ...items | 被删除元素组成的数组 | ✅ |
// 增删元素示例
const fruits = ['apple', 'banana'];
// 添加元素
fruits.push('orange'); // ['apple', 'banana', 'orange']
fruits.unshift('kiwi'); // ['kiwi', 'apple', 'banana', 'orange']
// 删除元素
fruits.pop(); // ['kiwi', 'apple', 'banana']
fruits.shift(); // ['apple', 'banana']
// 添加:在索引1处删除0个元素,添加2个元素
fruits.splice(1, 0, 'mango', 'grape');
// ['apple', 'mango', 'grape', 'banana']
// 删除:从索引2开始删除1个元素
fruits.splice(2, 1); // ['apple', 'mango', 'banana']
// 替换:将索引1处的元素替换为指定元素
fruits.splice(1,1,'orange'); //['apple', 'orange', 'banana']
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); // 1
numbers.lastIndexOf(12); // 3
numbers.includes(130); // true
// 条件查找
const found = numbers.find(num => num > 10); // 12
const foundIndex = numbers.findIndex(num => num > 100); // 4
// 安全访问
numbers.at(1); // 12
numbers.at(-1); // 44(最后一个元素)
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)); // 2, 4, 6, 8
// 转换
const doubled = numbers.map(num => num * 2); // [2, 4, 6, 8]
const evens = numbers.filter(num => num % 2 === 0); // [2, 4]
// 聚合
const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 10
// 扁平化
const nested = [1, [2, 3], [4, [5]]];
nested.flat(); // [1, 2, 3, 4, [5]]
nested.flat(2); // [1, 2, 3, 4, 5]
// 先map后扁平化
const phrases = ["hello world", "goodbye moon"];
const words = phrases.flatMap(phrase => phrase.split(" "));
// ["hello", "world", "goodbye", "moon"]
4. 排序与操作方法
方法 | 概念解释 | 参数说明 | 返回值 | 是否改变原数组 |
---|
sort | 对数组元素进行排序 | compareFunction(a, b)? | 排序后的数组 | ✅ |
reverse | 反转数组元素顺序 | 无 | 反转后的数组 | ✅ |
slice | 返回数组的一部分浅拷贝 | start?, end? :支持负数 | 新数组 | ❌ |
concat | 合并两个或多个数组 | ...arraysOrValues:数组或值 | 新数组 | ❌ |
join | 将数组元素连接为字符串 | separator?(默认逗号) | 字符串 | ❌ |
// 排序与操作示例
const fruits = ['banana', 'apple', 'cherry'];
// 排序
fruits.sort(); // ['apple', 'banana', 'cherry'](字典序)
// 自定义排序
const numbers = [40, 100, 1, 5, 25];
numbers.sort((a, b) => a - b); // [1, 5, 25, 40, 100]
numbers.sort((a, b) => b - a); // [100, 40, 25, 5, 1]
// 反转
fruits.reverse(); // ['cherry', 'banana', 'apple']
// 切片
const sliced = fruits.slice(1, 3); // ['banana', 'apple']
const sliced1 = fruits.slice(1); // ['banana', 'apple']
const sliced2 = fruits.slice(-1); // ['apple']
// 连接
const moreFruits = fruits.concat(['orange', 'kiwi']);
// ['cherry', 'banana', 'apple', 'orange', 'kiwi']
const moreFruits1 = fruits.concat(‘mengo');
// ['cherry', 'banana', 'apple', 'orange', 'kiwi','mengo']
// 连接为字符串
fruits.join(' and '); // 'cherry and banana and apple'
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); // false
ages.some(age => age > 18); // true
// 填充
const emptyArray = new Array(3);
emptyArray.fill('default'); // ['default', 'default', 'default']
// 复制内部元素到target位置
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3, 5); // [4, 5, 3, 4, 5](将索引3-5复制到索引0)
// 类型检查
Array.isArray(arr); // true
Array.isArray({}); // false
二、对象方法详解
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);
// { name: 'Alice', age: 30, title: 'Developer' }
// 获取键、值、条目
Object.keys(person); // ['name', 'age']
Object.values(person); // ['Alice', 30]
Object.entries(person); // [['name', 'Alice'], ['age', 30]]
//检查对象是否有置顶属性
Object.hasOwn(person,'name'); //true
// 冻结对象
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');
// { value: 1, writable: false, enumerable: true, configurable: false }
// 原型操作
const parent = { greet() { return 'Hello'; } };
const child = Object.create(parent); // 创建继承parent的对象
Object.getPrototypeOf(child) === parent; // true
// 设置原型
const newProto = { bye() { return 'Goodbye'; } };
Object.setPrototypeOf(child, newProto);
child.bye(); // 'Goodbye'
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); // true(不同于 ===)
Object.is(0, -0); // false(不同于 ===)
// 从键值对创建对象
const entries = [['name', 'Bob'], ['age', 25]];
const newObj = Object.fromEntries(entries);
// { name: 'Bob', age: 25 }
// 检查对象是否在原型链中
Array.prototype.isPrototypeOf([]); // true
// 检查自身属性
Object.hasOwn(newObj, 'name'); // true
Object.hasOwn(newObj, 'toString'); // false(继承属性)
// 防止扩展
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);
/*
{
vegetables: [{name:'asparagus', type:'vegetables'}],
fruit: [{name:'bananas', type:'fruit'}],
meat: [{name:'goat', type:'meat'}]
}
*/
// 深拷贝
const original = { a: 1, b: { c: 2 } };
const arr = [1,2,[3,4,[55]]];
const copy = structuredClone(original); // { a: 1, b: { c: 2 } }
const copyArr = structuredClone(arr); // [1,2,[3,4,[55]]]
三、最佳实践与性能优化
1. 数组操作黄金法则
方法选择指南:
- 增删元素:
push()
/pop()
/splice()
- 查询转换:
slice()
/concat()
/join()
- 迭代处理:
- 简单遍历 →
forEach()
- 转换元素 →
map()
- 筛选元素 →
filter()
- 聚合计算 →
reduce()
- 查找元素 →
find()
/findIndex()
- 排序操作:
sort()
/reverse()
- ES6+新特性:
flat()
/flatMap()
/includes()
性能陷阱:
// 1. 避免在循环中创建函数
// 差
const results = data.map(item => {
return processItem(item); // 每次迭代创建新函数
});
// 优
function process(item) { /*...*/ }
const results = data.map(process);
// 2. 减少不必要的中间数组
// 差
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;
}, []);
// 3. 大数据集使用TypedArray
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()
设计模式:
// 1. 工厂模式
function createUser(name) {
return Object.assign(Object.create(userProto), {
name,
createdAt: new Date()
});
}
// 2. 组合模式
const canEat = { eat() { /*...*/ } };
const canWalk = { walk() { /*...*/ } };
function createPerson(name) {
return Object.assign({ name }, canEat, canWalk);
}
// 3. 观察者模式
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];
// 方法1: Set + 展开运算符
const unique1 = [...new Set(numbers)].sort((a, b) => a - b);
// 方法2: filter + indexOf
const unique2 = numbers
.filter((num, index) => numbers.indexOf(num) === index)
.sort((a, b) => b - a); // 降序
// 方法3: reduce
const unique3 = numbers.reduce((acc, num) => {
if (!acc.includes(num)) acc.push(num);
return acc;
}, []).sort((a, b) => a - b);
console.log(unique1); // [1, 2, 3, 4, 5]
console.log(unique2); // [5, 4, 3, 2, 1]
console.log(unique3); // [1, 2, 3, 4, 5]
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);
/*
{
api: { baseURL: 'https://api.example.com', timeout: 30000 },
logging: { level: 'info' },
features: { analytics: true }
}
*/
3. 数据转换与处理
// 从API获取的数据
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 }
];
// 1. 获取IT部门员工
const itEmployees = apiResponse.filter(emp => emp.department === 'IT');
// 2. 计算IT部门平均薪资
const totalSalary = itEmployees.reduce((sum, emp) => sum + emp.salary, 0);
const avgSalary = totalSalary / itEmployees.length;
// 3. 转换为名称-薪资映射
const salaryMap = Object.fromEntries(
itEmployees.map(emp => [emp.name, emp.salary])
);
// { Bob: 80000, Charlie: 75000 }
// 4. 按薪资排序
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);
// { name: 'Alice', email: 'alice@example.com', ... }
// 验证表单数据
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);
/*
{
'user.name': 'Alice',
'user.address.city': 'Paris',
'user.address.country': 'France',
'roles': ['admin', 'editor']
}
*/
总结
掌握 JavaScript 数组和对象的方法是成为高效开发者的关键。本文详细介绍了:
- 数组方法:按功能分组(增删、查找、迭代、排序等)
- 对象方法:基本操作、属性描述、原型方法等
- 项目实践:数据转换、表单处理、状态管理等应用场景
- 最佳实践:性能优化、避免陷阱、现代特性应用
通过理解这些方法的原理和应用场景,结合项目实践中的示例,你将能够编写更简洁、高效和可维护的 JavaScript 代码。记住,选择合适的方法往往比编写复杂逻辑更重要!
以上就是JavaScript数组与对象方法完全指南的详细内容,更多关于JavaScript数组与对象方法的资料请关注脚本之家其它相关文章!