JavaScript 数组和对象方法完全指南(复习版)

51 阅读6分钟

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

数组方法

创建和初始化数组

// 字面量语法
const arr1 = [1, 2, 3];

// 构造函数
const arr2 = new Array(3);       // 创建长度为3的空数组
const arr3 = new Array(1, 2, 3); // 创建包含1,2,3的数组

// Array.of() - 创建包含所有参数的新数组
const arr4 = Array.of(3);        // [3] (不同于Array(3))
const arr5 = Array.of(1, 2, 3);  // [1, 2, 3]

// Array.from() - 从类数组或可迭代对象创建新数组
const arr6 = Array.from("hello"); // ["h", "e", "l", "l", "o"]
const arr7 = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]

数组基本操作

添加/删除元素
// push() - 在数组末尾添加元素,返回新长度
const arr = [1, 2, 3];
arr.push(4, 5);     // 返回5,arr现在是[1, 2, 3, 4, 5]

// pop() - 移除并返回数组的最后一个元素
const last = arr.pop(); // 返回5,arr现在是[1, 2, 3, 4]

// unshift() - 在数组开头添加元素,返回新长度
arr.unshift(0);     // 返回5,arr现在是[0, 1, 2, 3, 4]

// shift() - 移除并返回数组的第一个元素
const first = arr.shift(); // 返回0,arr现在是[1, 2, 3, 4]

// splice() - 添加/删除元素
arr.splice(1, 2);       // 从索引1开始删除2个元素,返回[2, 3],arr变为[1, 4]
arr.splice(1, 0, 2, 3); // 从索引1开始插入元素,返回[],arr变为[1, 2, 3, 4]
查找元素
const arr = [1, 2, 3, 4, 5, 3];

// indexOf() - 返回首个匹配元素的索引,未找到返回-1
arr.indexOf(3);     // 返回2
arr.indexOf(3, 3);  // 从索引3开始搜索,返回5

// lastIndexOf() - 返回最后一个匹配元素的索引,未找到返回-1
arr.lastIndexOf(3); // 返回5

// includes() - 检查数组是否包含某元素,返回布尔值
arr.includes(3);    // 返回true
arr.includes(6);    // 返回false

// find() - 返回满足测试函数的第一个元素的值
arr.find(x => x > 3);       // 返回4

// findIndex() - 返回满足测试函数的第一个元素的索引
arr.findIndex(x => x > 3);  // 返回3

// findLast() - 从后向前查找满足测试函数的第一个元素的值 (ES2023)
arr.findLast(x => x > 2);   // 返回5

// findLastIndex() - 从后向前查找满足测试函数的第一个元素的索引 (ES2023)
arr.findLastIndex(x => x > 2); // 返回4
遍历数组
const arr = [1, 2, 3];

// forEach() - 为每个元素执行回调函数
arr.forEach((value, index, array) => {
  console.log(value, index, array);
});

// map() - 创建一个新数组,其结果是对每个元素调用函数后的返回值
const doubled = arr.map(x => x * 2); // [2, 4, 6]

// filter() - 创建一个新数组,包含通过测试函数的所有元素
const evenNumbers = arr.filter(x => x % 2 === 0); // [2]

// reduce() - 将数组减少为单个值
const sum = arr.reduce((acc, curr) => acc + curr, 0); // 6

// reduceRight() - 从右到左应用reduce
const result = arr.reduceRight((acc, curr) => acc - curr, 0); // ((0-3)-2)-1 = -6

// every() - 测试所有元素是否都通过了测试函数
const allPositive = arr.every(x => x > 0); // true

// some() - 测试是否至少有一个元素通过了测试函数
const hasEven = arr.some(x => x % 2 === 0); // true

// for...of - ES6引入的遍历可迭代对象的方法
for (const item of arr) {
  console.log(item);
}
排序和操作
// sort() - 对数组元素进行排序
const arr = [3, 1, 4, 2];
arr.sort();                           // [1, 2, 3, 4]
arr.sort((a, b) => b - a);            // [4, 3, 2, 1] (降序)

// reverse() - 反转数组中元素的顺序
arr.reverse();                        // [1, 2, 3, 4]

// fill() - 用静态值填充数组
const filled = new Array(3).fill(7);  // [7, 7, 7]
arr.fill(0, 1, 3);                    // [1, 0, 0, 4] (从索引1到3填充0)

// copyWithin() - 复制数组的一部分到同一数组中的另一个位置
[1, 2, 3, 4, 5].copyWithin(0, 3);     // [4, 5, 3, 4, 5] (从索引3复制到索引0)
数组转换和合并
const arr = [1, 2, 3];

// join() - 将数组转换为字符串
arr.join();         // "1,2,3"
arr.join('-');      // "1-2-3"

// concat() - 合并两个或多个数组
const arr2 = arr.concat([4, 5], 6);   // [1, 2, 3, 4, 5, 6]

// slice() - 返回数组的一部分的浅拷贝
arr.slice(1);       // [2, 3] (从索引1到结束)
arr.slice(1, 2);    // [2] (从索引1到索引2,不包括索引2)

// flat() - 扁平化嵌套数组
const nested = [1, [2, [3, 4]]];
nested.flat();      // [1, 2, [3, 4]] (默认深度为1)
nested.flat(2);     // [1, 2, 3, 4] (深度为2)

// flatMap() - 先映射每个元素,然后扁平化结果
const arr3 = [1, 2, 3];
arr3.flatMap(x => [x, x * 2]);        // [1, 2, 2, 4, 3, 6]
数组迭代器方法
const arr = ['a', 'b', 'c'];

// entries() - 返回键/值对迭代器
const entries = arr.entries();
console.log(entries.next().value);    // [0, "a"]

// keys() - 返回键迭代器
const keys = arr.keys();
console.log(keys.next().value);       // 0

// values() - 返回值迭代器
const values = arr.values();
console.log(values.next().value);     // "a"
静态方法
// Array.isArray() - 检查值是否为数组
Array.isArray([]);      // true
Array.isArray({});      // false

ES2022+新增方法

// at() - 接受整数值并返回该索引的项目,允许负索引
const arr = [1, 2, 3, 4, 5];
arr.at(1);      // 2
arr.at(-1);     // 5 (最后一个元素)

// toSorted(), toReversed(), toSpliced() - 不改变原数组的排序、反转和拼接方法 (ES2023)
const original = [3, 1, 2];
const sorted = original.toSorted();                // [1, 2, 3]
const reversed = original.toReversed();            // [2, 1, 3]
const spliced = original.toSpliced(1, 1, 4, 5);    // [3, 4, 5, 2]
console.log(original);                             // [3, 1, 2] (原数组未改变)

// with() - 返回数组的副本,并在指定索引处替换值 (ES2023)
const arr2 = [1, 2, 3, 4, 5];
const newArr = arr2.with(2, 6);       // [1, 2, 6, 4, 5]
console.log(arr2);                    // [1, 2, 3, 4, 5] (原数组未改变)

// group() 和 groupToMap() - 按照测试函数的结果对数组元素进行分组 (提案阶段)
// 注意:这些方法尚未被广泛支持

// 模拟group()实现:
const inventory = [
  { name: "asparagus", type: "vegetables" },
  { name: "bananas", type: "fruit" },
  { name: "goat", type: "meat" }
];

// 使用reduce模拟group()
const grouped = inventory.reduce((acc, item) => {
  if (!acc[item.type]) {
    acc[item.type] = [];
  }
  acc[item.type].push(item);
  return acc;
}, {});

对象方法

创建对象

// 对象字面量
const obj1 = { name: "John", age: 30 };

// 构造函数
const obj2 = new Object();
obj2.name = "John";
obj2.age = 30;

// Object.create() - 使用现有对象作为新创建对象的原型
const person = { isHuman: true };
const john = Object.create(person);
john.name = "John";  // john继承了isHuman属性

属性操作

const obj = { name: "John", age: 30 };

// 访问属性
obj.name;            // "John"
obj["name"];         // "John"

// 添加/修改属性
obj.job = "Developer";
obj["salary"] = 100000;

// 删除属性
delete obj.age;      // 返回true,删除成功

对象方法

属性检查和枚举
const obj = { name: "John", age: 30 };
Object.defineProperty(obj, "ssn", { 
  value: "123-45-6789", 
  enumerable: false 
});

// hasOwnProperty() - 检查对象是否具有指定的自有属性
obj.hasOwnProperty("name");       // true
obj.hasOwnProperty("toString");   // false (继承的方法)

// propertyIsEnumerable() - 检查属性是否可枚举
obj.propertyIsEnumerable("name"); // true
obj.propertyIsEnumerable("ssn");  // false

// in操作符 - 检查属性是否在对象或其原型链中
"name" in obj;       // true
"toString" in obj;   // true (原型链上的方法)

// Object.keys() - 返回对象自身可枚举属性的名称数组
Object.keys(obj);    // ["name", "age"] (不包括ssn,因为它不可枚举)

// Object.values() - 返回对象自身可枚举属性的值数组
Object.values(obj);  // ["John", 30]

// Object.entries() - 返回对象自身可枚举属性的[key, value]对数组
Object.entries(obj); // [["name", "John"], ["age", 30]]

// Object.getOwnPropertyNames() - 返回对象自身所有属性的名称数组(包括不可枚举属性)
Object.getOwnPropertyNames(obj);  // ["name", "age", "ssn"]

// Object.getOwnPropertySymbols() - 返回对象自身所有Symbol属性的数组
const sym = Symbol("key");
obj[sym] = "Symbol value";
Object.getOwnPropertySymbols(obj); // [Symbol(key)]

// Object.getOwnPropertyDescriptors() - 返回对象所有属性的描述符
const descriptors = Object.getOwnPropertyDescriptors(obj);
// { 
//   name: {value: "John", writable: true, enumerable: true, configurable: true},
//   age: {value: 30, writable: true, enumerable: true, configurable: true},
//   ssn: {value: "123-45-6789", writable: false, enumerable: false, configurable: false}
// }
对象操作和合并
// Object.assign() - 将所有可枚举属性从一个或多个源对象复制到目标对象
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };
const result = Object.assign(target, source); // target和result都是{a: 1, b: 3, c: 4}

// 展开运算符 - ES6+中合并对象的方式 (不修改原始对象)
const merged = { ...target, ...source }; // {a: 1, b: 3, c: 4}

// Object.freeze() - 冻结对象,防止修改
const frozen = { x: 1 };
Object.freeze(frozen);
frozen.x = 2;        // 在严格模式下会抛出错误,否则静默失败
frozen.x;            // 仍然是1
Object.isFrozen(frozen); // true

// Object.seal() - 密封对象,防止添加或删除属性,但允许修改现有属性
const sealed = { y: 1 };
Object.seal(sealed);
sealed.y = 2;        // 可以修改
sealed.z = 3;        // 在严格模式下会抛出错误,否则静默失败
delete sealed.y;     // 在严格模式下