javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript数组与对象方法

JavaScript数组与对象方法完全指南

作者:markyankee101

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检查是否为数组valueBoolean
// 其他方法示例
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, value2Boolean
Object.fromEntries将键值对列表转为对象iterable新对象
Object.isPrototypeOf()检查对象是否在原型链中obj: 要检查的对象Boolean
Object.hasOwn检查对象是否具有指定属性(自身属性)obj, propBoolean
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. 数组操作黄金法则

方法选择指南

性能陷阱

// 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. 对象操作专业建议

方法选择指南

设计模式

// 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 数组和对象的方法是成为高效开发者的关键。本文详细介绍了:

  1. 数组方法:按功能分组(增删、查找、迭代、排序等)
  2. 对象方法:基本操作、属性描述、原型方法等
  3. 项目实践:数据转换、表单处理、状态管理等应用场景
  4. 最佳实践:性能优化、避免陷阱、现代特性应用

通过理解这些方法的原理和应用场景,结合项目实践中的示例,你将能够编写更简洁、高效和可维护的 JavaScript 代码。记住,选择合适的方法往往比编写复杂逻辑更重要!

以上就是JavaScript数组与对象方法完全指南的详细内容,更多关于JavaScript数组与对象方法的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文