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; // 在严格模式下