跳到主要内容

集合引用类型

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; // 读取字节长度
类型
TypeValue RangeSize in bytesDescriptionEquivalent C type
Int8-128 to 12718-bit two's complement signed integerint8_t
Uint80 to 25518-bit unsigned integeruint8_t
Int16-32768 to 32767216-bit two's complement signed integerint16_t
Uint160 to 65535216-bit unsigned integeruint16_t
Int32-2147483648 to 2147483647432-bit two's complement signed integerint32_t
Uint320 to 4294967295432-bit unsigned integeruint32_t
Float321.2E-38 to 3.4E38432-bit IEEE floating point number (7 significant digits e.g., 1.1234567)float
Float645E-324 to 1.8E308864-bit IEEE floating point number (16 significant digits e.g., 1.123...15)double
BigInt64-2^63 to 2^63 - 1864-bit two's complement signed integerint64_t (signed long long)
BigUint640 to 2^64 - 1864-bit unsigned integeruint64_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
类型
TypeValue RangeSize in bytesDescriptionWeb IDL typeEquivalent C type
Int8Array-128 to 12718-bit two's complement signed integerbyteint8_t
Uint8Array0 to 25518-bit unsigned integeroctetuint8_t
Int16Array-32768 to 32767216-bit two's complement signed integershortint16_t
Uint16Array0 to 65535216-bit unsigned integerunsigned shortuint16_t
Int32Array-2147483648 to 2147483647432-bit two's complement signed integerlongint32_t
Uint32Array0 to 4294967295432-bit unsigned integerunsigned longuint32_t
Float32Array1.2E-38 to 3.4E38432-bit IEEE floating point number (7 significant digits e.g., 1.1234567)unrestricted floatfloat
Float64Array5E-324 to 1.8E308864-bit IEEE floating point number (16 significant digits e.g., 1.123...15)unrestricted doubledouble
BigInt64Array-2^63 to 2^63 - 1864-bit two's complement signed integerbigintint64_t (signed long long)
BigUint64Array0 to 2^64 - 1864-bit unsigned integerbigintuint64_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]