集合引用类型
array
array 基础
array
- 动态大小, 有序列表, 不同种类元素;
- 特殊对象, 即键为索引值, 值为数组元素;
创建 array
// 构造函数
let colors = new Array(20); // 作为 length 属性, 未初始化数组元素赋值为 undefined
let colors = new Array(10, 20); // 作为两个数组元素
// 数组字面量
let colors = ["red", "blue", "green"];
Array Holes
- ES6 根据 [] 中连续的, 确定数组元素数量, 默认赋值为 undefined;
console.log(Array.of(...[, , ,])); // [undefined, undefined, undefined]
伪数组
伪数组
- 具有 length 属性的对象, 可称为类数组对象;
- arguments;
- 部分 DOM 方法返回对象;
- 无法调用数组方法;
伪数组转换为数组
Array.prototype.slice.call(arrayLike);
Array.prototype.splice.call(arrayLike, 0);
Array.from(arrayLike);
[...arrayLike];
遍历伪数组
- 使用数组方法 + call();
- 将其转换为数组;
Array.prototype.forEach.call(arguments, (a) => console.log(a));
数组索引和长度
索引
- 索引从 0 开始;
- 若索引小于数组长度, 赋值或访问值操作;
- 若索引大于数组长度, 自动扩充数组至索引位置, 并赋值 undefined;
长度
- 可手动修改 length 属性;
- 自动创建缺失数组元素, 并赋值 undefined;
- 自动舍去额外数组元素;
- length 最大为 4, 294, 967, 295;
常用 API
变异方法和非变异方法
- 变异方法: 修改原始数组的方法;
- 非变异方法: 不修改原始数组的方法;
常用 API
- Array(arrayLength?: number): any[] 构造函数: 创建新数组;
- Array.from(arrayLike: any, mapFn?: (element: any, index: number) => any, thisArg?: any): any[] 静态方法: 从类数组或可迭代对象创建新数组;
Array.fromAsync(iterableOrArrayLike: any, mapFn?: (element: any, index: number) => any, thisArg?: any): Promise<any[]>静态方法: 异步从类数组或可迭代对象创建新数组;- Array.isArray(value: any): boolean 静态方法: 判断 value 是否为数组;
- Array.of(...elements: any[]): any[] 静态方法: 根据参数创建新数组;
- Array[Symbol.species]: Function 静态属性: 用于创建派生对象的构造函数;
- Array.prototype.at(index: number): any: 返回 index 对应元素, 支持负数索引;
- Array.prototype.concat(...items: (any | any[])[]): any[]: 合并两个或多个数组;
- Array.prototype.copyWithin(target: number, start: number, end?: number): this: 浅复制数组的一部分到同一数组中的另一个位置;
Array.prototype.entries(): IterableIterator<[number, any]>: 返回一个新的 Array Iterator 对象, 包含数组中每个索引的键/值对;- Array.prototype.every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean: 测试数组的所有元素是否都通过了指定函数的测试;
- Array.prototype.fill(value: any, start?: number, end?: number): this: 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素;
- Array.prototype.filter(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): any[]: 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素;
- Array.prototype.find(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): any | undefined: 返回数组中满足提供的测试函数的第一个元素的值;
- Array.prototype.findIndex(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): number: 返回数组中满足提供的测试函数的第一个元素的索引;
- Array.prototype.findLast(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): any | undefined: 反向遍历数组, 返回满足提供的测试函数的第一个元素的值;
- Array.prototype.findLastIndex(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): number: 反向遍历数组, 返回满足提供的测试函数的第一个元素的索引;
- Array.prototype.flat(depth?: number): any[]: 按照一个可指定的深度递归遍历数组, 并将所有元素与遍历到的子数组中的元素合并为一个新数组返回;
- Array.prototype.flatMap(callback: (this: any, value: any, index: number, array: any[]) => any | readonly any[], thisArg?: any): any[]: 首先使用映射函数映射每个元素, 然后将结果压缩成一个新数组;
- Array.prototype.forEach(callbackfn: (value: any, index: number, array: any[]) => void, thisArg?: any): void: 对数组的每个元素执行一次给定的函数;
- Array.prototype.includes(searchElement: any, fromIndex?: number): boolean: 判断一个数组是否包含一个指定的值;
- Array.prototype.indexOf(searchElement: any, fromIndex?: number): number: 返回在数组中可以找到一个给定元素的第一个索引, 如果不存在, 则返回 -1;
- Array.prototype.join(separator?: string): string: 将一个数组的所有元素连接成一个字符串;
Array.prototype.keys(): IterableIterator<number>: 返回一个包含数组中每个索引键的 Array Iterator 对象;- Array.prototype.lastIndexOf(searchElement: any, fromIndex?: number): number: 返回指定元素在数组中的最后一个的索引;
- Array.prototype.map(callbackfn: (value: any, index: number, array: any[]) => any, thisArg?: any): any[]: 创建一个新数组, 其结果是该数组中的每个元素是调用一次提供的函数后的返回值;
- Array.prototype.pop(): any | undefined: 从数组中删除最后一个元素, 并返回该元素的值;
- Array.prototype.push(...items: any[]): number: 将一个或多个元素添加到数组的末尾, 并返回该数组的新长度;
- Array.prototype.reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue?: any): any: 对数组中的每个元素执行一个由您提供的reducer函数(升序执行), 将其结果汇总为单个返回值;
- Array.prototype.reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue?: any): any: 接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值;
- Array.prototype.reverse(): this: 将数组中元素的位置颠倒, 并返回该数组;
- Array.prototype.shift(): any | undefined: 从数组中删除第一个元素, 并返回该元素的值;
- Array.prototype.slice(start?: number, end?: number): any[]: 返回一个新的数组对象, 这一对象是一个由 begin 和 end 决定的原数组的浅拷贝;
- Array.prototype.some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean: 测试数组中是不是至少有1个元素通过了被提供的函数测试;
- Array.prototype.sort(compareFn?: (a: any, b: any) => number): this: 用原地算法对数组的元素进行排序, 并返回数组;
- Array.prototype.splice(start: number, deleteCount?: number, ...items: any[]): any[]: 通过删除或替换现有元素或者原地添加新的元素来修改数组, 并以数组形式返回被修改的内容;
- Array.prototype.toLocaleString(): string: 返回一个字符串表示数组中的元素;
- Array.prototype.toReversed(): any[]: 返回一个元素顺序相反的新数组;
- Array.prototype.toSorted(compareFn?: (a: any, b: any) => number): any[]: 返回一个新数组, 其元素按升序排列;
- Array.prototype.toSpliced(start: number, deleteCount?: number, ...items: any[]): any[]: 返回一个新数组, 并在给定的索引处删除和/或替换了一些元素;
- Array.prototype.toString(): string: 返回一个字符串, 表示指定的数组及其元素;
- Array.prototype.unshift(...items: any[]): number: 将一个或多个元素添加到数组的开头, 并返回该数组的新长度;
Array.prototype.values(): IterableIterator<any>: 返回一个新的 Array Iterator 对象, 该对象包含数组每个索引的值;- Array.prototype.with(index: number, value: any): any[]: 返回一个新数组, 其中给定索引处的元素替换为给定值;
Typed Arrays
ArrayBuffer
ArrayBuffer
- 一个内存分配块;
- typed array 和 views 的基本单元;
创建 ArrayBuffer
// 分配 16 bytes 内存
const buf = new ArrayBuffer(16);
// buf 的内存大小
const length = buf.byteLength; // 16
特性
- ArrayBuffer 一旦创建;
- 其内存大小无法改变且无法被读写;
- 若要读写须使用 DataViews 或 typed array;
DataViews
基础
// 以 1 bytes 为基本单位
const buffer = new ArrayBuffer(2);
// 读取 buffer, 从 0 读取, 读取 buffer.length 个字节
const view = new DataView(buffer, 0, buffer.length);
const bf = view.buffer; // 读取的 buffer
const byteOffset = view.byteOffset; // 读取偏移量
const byteLength = view.byteLength; // 读取字节长度
类型
| Type | Value Range | Size in bytes | Description | Equivalent C type |
|---|---|---|---|---|
| Int8 | -128 to 127 | 1 | 8-bit two's complement signed integer | int8_t |
| Uint8 | 0 to 255 | 1 | 8-bit unsigned integer | uint8_t |
| Int16 | -32768 to 32767 | 2 | 16-bit two's complement signed integer | int16_t |
| Uint16 | 0 to 65535 | 2 | 16-bit unsigned integer | uint16_t |
| Int32 | -2147483648 to 2147483647 | 4 | 32-bit two's complement signed integer | int32_t |
| Uint32 | 0 to 4294967295 | 4 | 32-bit unsigned integer | uint32_t |
| Float32 | 1.2E-38 to 3.4E38 | 4 | 32-bit IEEE floating point number (7 significant digits e.g., 1.1234567) | float |
| Float64 | 5E-324 to 1.8E308 | 8 | 64-bit IEEE floating point number (16 significant digits e.g., 1.123...15) | double |
| BigInt64 | -2^63 to 2^63 - 1 | 8 | 64-bit two's complement signed integer | int64_t (signed long long) |
| BigUint64 | 0 to 2^64 - 1 | 8 | 64-bit unsigned integer | uint64_t (unsigned long long) |
Big-Endian 和 Little-Endian
- 字节存储的顺序, 以 1 字节为基本单位, 即 8 位;
- Big-Endian;
- 最高位的字节存储在开头, 最低位的字节储存在末尾;
- Little-Endian;
- 与 Big-Endian 相反;
const buf = new ArrayBuffer(2);
const view = new DataView(buf);
view.setUint8(0, 0x80);
view.setUint8(1, 0x01);
// 0x8 0x0 0x0 0x1
// big-endian
// 0x8001 = 8*16^3 + 1*16^0 = 32768 + 1 = 32769
const big = view.getUint16(0); // 32769
// little-endian
// 0x0180 = 1*16^2 + 8*16^1 = 256 + 128 = 384
console.log(view.getUint16(0, true)); // 384
// Wlittle-endian Uint16
view.setUint16(0, 0x0002, true);
// 0x0 0x2 0x0 0x0
// 0000 0010 0000 0000
TypedArray
创建 TypedArray
const buf = new ArrayBuffer(12);
// 未初始化值为 0
const ints = new Int32Array(buf);
const ints2 = Int16Array.from([3, 5, 7, 9]);
const floats = Float32Array.of(3.14, 2.718, 1.618);
// TypedArray 元素数量
const length = ints.length; //3
// TypedArray 对应的 ArrayBuffer
const buffer = ints.buffer; // buf
// TypedArray 字节长度
const buffer = ints.byteLength; //12
// TypedArray 元素字节长度
const byteLength = ints.BYTES_PER_ELEMENT; //4
类型
| Type | Value Range | Size in bytes | Description | Web IDL type | Equivalent C type |
|---|---|---|---|---|---|
| Int8Array | -128 to 127 | 1 | 8-bit two's complement signed integer | byte | int8_t |
| Uint8Array | 0 to 255 | 1 | 8-bit unsigned integer | octet | uint8_t |
| Int16Array | -32768 to 32767 | 2 | 16-bit two's complement signed integer | short | int16_t |
| Uint16Array | 0 to 65535 | 2 | 16-bit unsigned integer | unsigned short | uint16_t |
| Int32Array | -2147483648 to 2147483647 | 4 | 32-bit two's complement signed integer | long | int32_t |
| Uint32Array | 0 to 4294967295 | 4 | 32-bit unsigned integer | unsigned long | uint32_t |
| Float32Array | 1.2E-38 to 3.4E38 | 4 | 32-bit IEEE floating point number (7 significant digits e.g., 1.1234567) | unrestricted float | float |
| Float64Array | 5E-324 to 1.8E308 | 8 | 64-bit IEEE floating point number (16 significant digits e.g., 1.123...15) | unrestricted double | double |
| BigInt64Array | -2^63 to 2^63 - 1 | 8 | 64-bit two's complement signed integer | bigint | int64_t (signed long long) |
| BigUint64Array | 0 to 2^64 - 1 | 8 | 64-bit unsigned integer | bigint | uint64_t (unsigned long long) |
常用 API
- Array 大多数 API;
类型位数和范围
- 若写入值位数大于类型对应位数, 从右向左截取对应位数;
- 若写入值大于对应类型取值范围, 基于补码自动转换成对应类型;
Map
Map 基础
Map
- 不重复键值对, 任意数据类型, 顺序存储;
- 使用 SameValueZero;
创建 Map
const m = new Map();
// 初始化
const m1 = new Map([
["key1", "val1"];
["key2", "val2"];
["key3", "val3"];
]); // 推荐使用
常用 API
Map<K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>构造函数: 创建 Map 对象;Map.groupBy<K, T>(items: Iterable<T>, keySelector: (item: T, index: number) => K): Map<K, T[]>静态方法: 根据 keySelector 分组;- Map[Symbol.species]: MapConstructor 静态属性: 用于创建派生对象的构造函数;
- Map.prototype.clear(): void: 清除所有键值对;
- Map.prototype.delete(key: K): boolean: 删除键为 key 的元素;
Map.prototype.entries(): IterableIterator<[K, V]>: 返回一个新的 Iterator 对象, 包含 Map 对象中每个元素的 [key, value] 数组;Map.prototype.forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void: 按插入顺序调用 callbackfn;- Map.prototype.get(key: K): V | undefined: 返回键为 key 的值;
- Map.prototype.getOrInsert(key: K, value: V): V: 如果 key 存在返回对应值, 否则插入 value 并返回;
- Map.prototype.getOrInsertComputed(key: K, producer: (key: K) => V): V: 如果 key 存在返回对应值, 否则执行 producer 插入并返回;
- Map.prototype.has(key: K): boolean: 判断 Map 是否包含键为 key 的元素;
Map.prototype.keys(): IterableIterator<K>: 返回一个新的 Iterator 对象, 包含 Map 对象中每个元素的 key;- Map.prototype.set(key: K, value: V): this: 添加或更新键值对;
Map.prototype.values(): IterableIterator<V>: 返回一个新的 Iterator 对象, 包含 Map 对象中每个元素的 value;Map.prototype[Symbol.iterator](): IterableIterator<[K, V]>: 返回 entries() 迭代器;- Map.prototype.size: number: 返回 Map 对象中键值对的数量;
map 和 object 的区别
- 键类型: map 可以是任意类型, object 只能是 string/symbol;
- 键顺序: map 根据插入顺序排序, object 键无序;
- 性能: map 具有更好的插入和删除性能, object 具有更好的查找性能;
- size: map 可直接获取 size, object 只能通过 key/value 等方法计算;
- 原型链: map 不存在原型链, object 可能因为原型链导致键被覆盖;
The WeakMap Type
WeakMap 基础
创建 WeakMap
- key 必须是一个 object;
- 保证 WeakMap 中的 value 只能通过 key 访问;
- 如果使用字面量类型, 访问 WeakMap 时, 无法区别字面量是初始化时的字面量;
const wm = new WeakMap();
const key1 = { id: 1 };
key2 = { id: 2 };
key3 = { id: 3 };
const m1 = new WeakMap([
[key1, "val1"];
[key2, "val2"];
[key3, "val3"];
]);
常用 API
- 同 Map;
Weak Keys
- WeakMap key 为弱引用;
- WeakMap 不会阻止作为 key 的 object 的回收;
const wm = new WeakMap();
const container = {
id: 1;
};
wm.set(container, "val");
container = null; // 垃圾回收
const wm = new Map();
const container = {
id: 1;
};
wm.set(container, "val");
container = null; // wm 中依旧存储 container, 不会垃圾回收
Non-Iterable Keys
- 由于 WeakMap 中的键值对可在任意时刻垃圾回收;
- Iterable 不具有存在意义;
- 进而导致无 clear(), keys(), values() 方法;
The Set Type
Set 基础
Set
- 唯一值, 任意数据类型, 顺序存储;
- 使用 SameValueZero;
创建 Set
const m = new Set();
// 创建并初始化
const s1 = new Set(["val1", "val2", "val3]);
// 元素数量
console.log(s1.size); // 3
常用 API
Set<T>(values?: readonly T[] | null): Set<T>构造函数: 创建 Set 对象;- Set[Symbol.species]: SetConstructor 静态属性: 用于创建派生对象的构造函数;
- Set.prototype.add(value: T): this: 添加元素;
- Set.prototype.clear(): void: 清除所有元素;
- Set.prototype.delete(value: T): boolean: 删除指定元素;
Set.prototype.difference(other: Set<T>): Set<T>: 返回当前 Set 与 other 的差集;Set.prototype.entries(): IterableIterator<[T, T]>: 返回一个新的 Iterator 对象, 包含 Set 对象中每个元素的 [value, value] 数组;Set.prototype.forEach(callbackfn: (value: T, key: T, set: Set<T>) => void, thisArg?: any): void: 按插入顺序调用 callbackfn;- Set.prototype.has(value: T): boolean: 判断 Set 是否包含指定元素;
Set.prototype.intersection(other: Set<T>): Set<T>: 返回当前 Set 与 other 的交集;Set.prototype.isDisjointFrom(other: Set<T>): boolean: 判断当前 Set 与 other 是否不相交;Set.prototype.isSubsetOf(other: Set<T>): boolean: 判断当前 Set 是否为 other 的子集;Set.prototype.isSupersetOf(other: Set<T>): boolean: 判断当前 Set 是否为 other 的超集;Set.prototype.keys(): IterableIterator<T>: 返回 values() 的别名;Set.prototype.symmetricDifference(other: Set<T>): Set<T>: 返回当前 Set 与 other 的对称差集;Set.prototype.union(other: Set<T>): Set<T>: 返回当前 Set 与 other 的并集;Set.prototype.values(): IterableIterator<T>: 返回一个新的 Iterator 对象, 包含 Set 对象中每个元素的 value;Set.prototype[Symbol.iterator](): IterableIterator<T>: 返回 values() 迭代器;- Set.prototype.size: number: 返回 Set 对象中元素的数量;
The WeakSet Type
WeakSet 基础
创建 WeakSet
const ws = new WeakSet();
// 创建并初始化
// value 只能是 object;
const val1 = { id: 1 };
val2 = { id: 2 };
val3 = { id: 3 };
const ws1 = new WeakSet([val1, val2, val3]);
key 类型约束原因
- 保证 WeakSet 中的 value 只能通过 value 对应 object 访问;
常用 API
- 同 Set;
Weak Keys
- 同 WeakMap;
const ws = new WeakSet();
const container = {
id: 1;
};
ws.set(container);
container = null; // 垃圾回收
const ws = new Set();
const container = {
id: 1;
};
ws.set(container);
container = null; // ws 中依旧存储 container, 不会垃圾回收
Non-Iterable Values
- 同 WeakMap;
拓展运算符
具有 default iterator 的集合引用类型
- Array;
- All typed arrays;
- Map;
- Set;
for..of
- 具有 default iterator 的集合引用类型均可用于 for...of 循环;
...运算符
- 集合引用类型均可使用 ... 进行拓展, 创建浅复制副本;
let arr1 = [1, 2, 3];
let arr2 = [...arr1];
console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3]
console.log(arr1 === arr2); // false
let arr1 = [{}];
let arr2 = [...arr1];
arr1[0].foo = "bar";
console.log(arr2[0]); // { foo: 'bar' }
不同类型之间的互操作性
let arr1 = [1, 2, 3];
// Copy array into typed array
let typedArr1 = Int16Array.of(...arr1);
let typedArr2 = Int16Array.from(arr1);
console.log(typedArr1); // Int16Array [1, 2, 3]
console.log(typedArr2); // Int16Array [1, 2, 3]
// Copy array into map
let map = new Map(arr1.map((x) => [x, "val" + x]));
console.log(map); // Map {1 => 'val 1' , 2 => 'val 2' , 3 => 'val 3' }
// Copy array in to set
let set = new Set(typedArr2);
console.log(set); // Set {1, 2, 3}
// Copy set back into array
let arr2 = [...set];
console.log(arr2); // [1, 2, 3]
最佳实践
深拷贝和浅拷贝
浅拷贝
- 复制对象和数组的引用地址, 而非其值;
- Object.assign;
- ...;
- slice();
- concat;
深拷贝
JSON
- 使用 JSON.parse() 和 JSON.stringify();
- 简单但无法处理 undefined 和函数;
const obj1 = { a: 1, b: { c: 2 } };
JSON.parse(JSON.stringify(obj1));
structuredClone()
- 新 API, 兼容性不好;
自定义拷贝
const deepClone = (obj, hash = new WeakMap()) => {
if (typeof obj !== "object" || obj === null) return obj;
if (hash.has(obj)) return hash.get(obj);
const newObj = Array.isArray(obj) ? [] : {};
hash.set(obj, newObj);
for (const key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
newObj[key] = deepClone(obj[key], hash);
}
return newObj;
};
const obj1 = {};
const obj2 = { a: 1 };
obj1.obj2 = obj2;
obj2.obj1 = obj1;
const obj3 = deepClone(obj1);
console.log(obj3.obj2.a); // 1
Array
去重数组
// 遍历 + indexof()
for (let i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
// 遍历 + include
for (var i = 0; i < arr.length; i++) {
if (!newArr.includes(arr[i])) {
newArr.push(arr[i]);
}
}
// 使用 filter()
arr.filter((item, index, arr) => arr.indexOf(item, 0) === index);
// 使用 set
Array.from(new Set(arr));
forEach 跳出循环
- forEach 无法跳出循环;
- forEach 的回调函数, 构成函数作用域, 使用 return 只是跳出回调函数;
- 若想跳出循环, 可使用 some 或者 every;
树形结构
扁平化
const flattenTree = (tree) => {
if (tree.children == null || tree.children.length === 0) {
return [tree];
} else {
let res = [tree];
for (const child of tree.children) {
res = res.concat(flattenTree(child));
}
delete tree.children;
return res;
}
};
const tree = {
value: 1,
children: [
{
value: 2,
children: [{ value: 4 }, { value: 5 }],
},
{
value: 3,
children: [
{ value: 6 },
{ value: 7 },
{
value: 8,
children: [{ value: 9 }, { value: 10 }],
},
],
},
],
};
console.log(flattenTree(tree));
根据 id 和 parentID 还原树形结构
const buildTree = (array, parentId = null) => {
return array.reduce((tree, cur) => {
if (cur.parentId === parentId) {
const children = buildTree(array, cur.id);
if (children.length > 0) cur.children = children;
tree.push(cur);
}
return tree;
}, []);
};
const data = [
{ id: 1, name: "Node 1", parentId: null },
{ id: 2, name: "Node 1.1", parentId: 1 },
{ id: 3, name: "Node 1.2", parentId: 1 },
{ id: 4, name: "Node 1.2.1", parentId: 3 },
{ id: 5, name: "Node 1.2.2", parentId: 3 },
{ id: 6, name: "Node 2", parentId: null },
{ id: 7, name: "Node 2.1", parentId: 6 },
{ id: 8, name: "Node 2.1.1", parentId: 7 },
{ id: 9, name: "Node 2.1.2", parentId: 7 },
{ id: 10, name: "Node 2.2", parentId: 6 },
];
const tree = buildTree(data);
console.log(tree);
手写数组方法
forEach
Array.prototype.myForEach = function (callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this);
}
};
const arr = [1, 2, 3, 4, 5];
arr.myForEach((item) => console.log(item));
Map
Array.prototype.myMap = function (callback) {
const result = [];
for (let i = 0; i < this.length; i++) {
result.push(callback(this[i], i, this));
}
return result;
};
const arr = [1, 2, 3];
const mappedArr = arr.myMap((x) => x * 2);
console.log(mappedArr); // [2, 4, 6]
filter
Array.prototype.myFilter = function (callback) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
const arr = [1, 2, 3, 4, 5];
const filteredArr = arr.myFilter((x) => x % 2 === 1);
console.log(filteredArr); // [1, 3, 5]
some
Array.prototype.mySome = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return true;
}
}
return false;
};
const arr = [1, 2, 3, 4, 5];
const isEven = (x) => x % 2 === 0;
console.log(arr.mySome(isEven)); // true
every
Array.prototype.myEvery = function (callback) {
for (let i = 0; i < this.length; i++) {
if (!callback(this[i], i, this)) {
return false;
}
}
return true;
};
const arr = [1, 2, 3, 4, 5];
const isEven = (x) => x % 2 === 0;
console.log(arr.myEvery(isEven)); // false
find
Array.prototype.myFind = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return this[i];
}
}
return undefined;
};
const arr = [1, 2, 3, 4, 5];
const isEven = (x) => x % 2 === 0;
console.log(arr.myFind(isEven)); // 2
reduce
Array.prototype.myReduce = function (callback, initialValue) {
let accumulator = initialValue === undefined ? undefined : initialValue;
for (let i = 0; i < this.length; i++) {
if (accumulator !== undefined) {
accumulator = callback.call(undefined, accumulator, this[i], i, this);
} else {
accumulator = this[i];
}
}
return accumulator;
};
const arr = [1, 2, 3, 4, 5];
const sum = (prev, curr) => prev + curr;
console.log(arr.myReduce(sum)); // 15
flat
Array.prototype.myFlat = function (depth = 1) {
const result = [];
const flatten = (arr, d) => {
arr.forEach((item) => {
if (Array.isArray(item) && d > 0) {
flatten(item, d - 1);
} else {
result.push(item);
}
});
};
flatten(this, depth);
return result;
};
const arr = [1, [2, [3, [4]], 5]];
console.log(arr.myFlat()); // [1, 2, [3, [4]], 5]
console.log(arr.myFlat(1)); // [1, 2, [3, [4]], 5]
console.log(arr.myFlat(2)); // [1, 2, 3, [4], 5]
console.log(arr.myFlat(3)); // [1, 2, 3, 4, 5]