跳到主要内容

集合引用类型

object

array

array 基础

array
  • 动态大小;
  • 有序列表;
  • 不同种类元素;
创建 array
  • Array() 构造函数;
  • array literal notation;
  • 未初始化数组元素赋值为 undefined;
let colors = new Array("red", "blue", "green");
let colors = ["red", "blue", "green"];
指定数组长度
  • 传入单个 int 类型参数作为 length 属性;
  • 其余类型使其为数组元素;
let colors = new Array(20);
let colors = new Array(10, 20);
Array Holes
  • ES6 根据 [] 中连续的 ,确定数组元素数量;
  • 默认赋值为 undefined;
console.log(Array.of(...[, , ,])); // [undefined, undefined, undefined]
数组和对象
  • 数组是一个特殊的对象,即键为索引值,值为数组元素的;
const arr = [1, 2, 3];
for (const key in arr) {
console.log(key); // 0 1 2
}

伪数组

伪数组
  • 具有 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 属性
  • 可手动修改 length 属性;
  • 自动创建缺失数组元素,并赋值 undefined;
  • 自动舍去额外数组元素;
  • length 最大为 4,294,967,295;
let colors = ["red", "blue", "green"];
colors.length = 4;
console.log(colors[3]); // undefined
let colors = ["red", "blue", "green"];
colors.length = 2;
console.log(colors[2]); // undefined

常用 API

变异方法和非变异方法
  • 变异方法:修改原始数组的方法;
  • 非变异方法:不修改原始数组的方法;
创建数组
// 根据 arrayLike 执行 mapFn, 根据返回结果创建数组;
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1, (x) => x ** 2); // [1, 4, 9, 16]
// 根据 elements 创建数组
Array.of(1, 2, 3, 4); // [1, 2, 3, 4]
判断数组
const arr = [];
Array.isArray(arr); // true
拓展数组
const arr = [6, 3];
const keys = arr.keys(); // [0, 1]
const values = arr.values(); // [6, 3]
const entries = arr.entries(); // [[0, 6], [1, 3]]
排序数组
const arr = [6, 3];
// 逆序排列
// 改变原数组
arr.reverse(); // [3, 6]
// 不改变原数组
const reversedItems = items.toReversed();

// 根据字符串形式顺序排列
// 改变原数组
const array1 = [1, 30, 4, 21, 100000];
// 不改变元素组
arr.sort(); // [1, 100000, 21, 30, 4]
const sortedMonths = months.toSorted();
// 自定义排序, 返回值 > 0, a 在后, 反之 a 在前, 0
const sortedValues = values.toSorted((a, b) => a > b);
替换
const array1 = [1, 2, 3, 4];
// 全部替换为 0
const array2 = array1.fill(0); // [0, 0, 0, 0]
// 将 [2, array1.length - 1) 替换为 0
const array3 = array1.fill(0, 2); // [1, 2, 0, 0]
// 将 [2, 4) 替换为 0
const array4 = array1.fill(0, 2, 4); // [1, 2, 0, 0]
// fill 替换值为引用对象, 所有值都指向同一个应用对象
const array5 = new Array(10).fill([]);

const ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// 将 [5, array1.length - 1) 替换为 [0, ...)
const ints1 = ints.copyWithin(5); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
// 将 [0, array1.length - 1) 替换为 [5, ...)
const ints2 = ints.copyWithin(0, 5);
console.log(ints); // [5, 6, 7, 8, 9, 5, 6, 7, 8, 9]
// 将 [0, 3) 替换为 [4, ...)
ints.copyWithin(4, 0, 3); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
转换
const array1 = [1, 2, "a", "1a"];
const str1 = array1.toString(); // "1,2,a,1a"
const str2 = array1.join(); // "1,2,a,1a"
const str2 = array1.join(""); // "12a1a"
const str2 = array1.join("-"); // "1-2-a-1a"
const animals = ["pigs", "goats", "sheep"];
// 添加至末尾
const count = animals.push("cows"); // 4
// 移除末尾元素
const popItem = animals.pop(); // 'cows'
队列
const animals = ["pigs", "goats", "sheep"];
// 添加至开头
const count = animals.unshift("cows"); // 4
// 移除开头元素
const popItem = animals.shift(); // 'cows'
链接数组
const array1 = ["a", "b", "c"];
const array2 = ["d", "e", "f"];
const array3 = array1.concat(array2); // ["a", "b", "c", "d", "e", "f"]
// 扁平化数组, 但只会处理一层
let colors = ["red", "green", "blue"];
let colors2 = colors.concat("yellow", ["black", ["brown"]]); // ["red", "green", "blue", "yellow", "black", ["brown"]]
切片
const animals = ["ant", "bison", "camel", "duck", "elephant"];
// 提取 [2, animals.length)
const str1 = animals.slice(2); // ["camel", "duck", "elephant"]
// 提取 [2, -1), 可使用负数索引
const str2 = animals.slice(2, -1); // ["camel", "duck"]
万能的 splice()
// 改变原数组
const months = ["Jan", "March", "April", "June"];
// 从 1 删除 0 个, 添加 Feb
months.splice(1, 0, "Feb");
// 从 4 删除 1 个
months.splice(4, 1);
// 从 4 删除 1 个, 添加 May
months.splice(4, 1, "May");
// 不改变原数组版本
const months2 = months.toSpliced(1, 0, "Feb");
搜索
const beasts = ["ant", "bison", "camel", "duck", "bison"];
// 返回第一个值为 bison 的索引
const index1 = beasts.indexOf("bison"); // 1
// 返回最后一个值为 bison 的索引
const index2 = beasts.lastIndexOf("bison"); // 4
// beasts 是否包含 bison, 使用 ===
const isInclude = beasts.includes("bison"); // true

const array1 = [5, 12, 8, 130, 44];
// 返回第一个回调函数返回值为 true 的数组值
const found = array1.find((element, index, array) => element > 10);
// 返回最后一个回调函数返回值为 true 的数组值
const found = array1.findLast((element, index, array) => element > 10);
// 返回第一个回调函数返回值为 true 的数组索引
const found = array1.findIndex((element, index, array) => element > 10);
// 返回最后一个回调函数返回值为 true 的数组索引
const found = array1.findLastIndex((element, index, array) => element > 10);
遍历数组
const array1 = [1, 30, 39, 29, 10, 13];
// 回调函数是否全部返回 true
// 若回调函数返回 false , evert() 立刻停止遍历返回 false
// 反之返回 true
const isEvery = array1.every((element, index, array) => element < 40); // true
// 回调函数至少有一个返回 true
// 若回调函数返回 true , some() 立刻停止遍历返回 true
// 反之返回 false
const isSome = array1.some((element, index, array) => element < 20); // true
// 创建回调函数返回 true 的 element 组成的数组
const filter = array1.filter((element, index, array) => element < 20); // [1, 10, 13]
// 创建回调函数返回值组成的数组
const map = array1.map((element, index, array) => element + 1); // [2, 31, 40, 30, 11, 14]
// 单纯迭代数组
array1.forEach((element, index, array) => {});
// 正序迭代计算, 初始值为 0
// accumulator 为上一次迭代计算后的值
// 0 为初始值, 缺省值为第一个元素值
const result = array1.reduce(
(accumulator, currentValue, currentIndex, array) =>
accumulator + currentValue;
0
); // 122
// 倒叙计算
const result = array1.reduceRight(
(accumulator, currentValue, currentIndex, array) =>
accumulator + currentValue;
0
);

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)
常用 API
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
// 从位置 1 写入 32767, Big-Endian 模式
view.setInt16(1, 32767);
// 读取位置 1
const value = view.getInt16(1);
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
const buffer = new ArrayBuffer(8);
const uint8 = new Uint8Array(buffer);
// 在位置 3 写入 [1, 2, 3]
uint8.set([1, 2, 3], 3); // [0, 0, 0, 1, 2, 3, 0, 0];
类型位数
  • 若写入值位数大于类型对应位数;
  • 从右向左截取对应位数;
类型范围
  • 若写入值大于对应类型取值范围;
  • 基于补码自动转换成对应类型;

Map

Map 基础

Map
  • 不重复键值对;
    • 使用 SameValueZero;
  • 任意数据类型;
  • 顺序存储;
创建 Map
const m = new Map();
// 初始化
const m1 = new Map([
["key1", "val1"];
["key2", "val2"];
["key3", "val3"];
]); // 推荐使用

常用 API

操作 Map
const map1 = new Map();
// 添加键值对, 可链式使用
map1.set("bar", "foo").set(1, "foobar").set(2, "baz");
// 读 key 对应值
console.log(map1.get("bar")); // "foo"
// 判断是否具有 key
console.log(map1.has("bar")); // true
// 删除键值对
console.log(map1.delete("bar")); // true
// 清空 Map
map1.clear();
迭代 Map
// Map 记录键值对的插入顺序;
// 并可根据插入顺序执行迭代操作;
const map = new Map([
["foo", 3];
["bar", {}];
]);
// 迭代 Map
map.forEach((element, index, map) => {
//..;
}, this);
// 返回 keys 迭代器
const iterator1 = map1.keys(); // ["foo", "bar"]
console.log(iterator1.next().value); // "foo"
// 返回 values 迭代器
const iterator1 = map1.values(); // ["foo", "bar"]
console.log(iterator1.next().value); // 3
// 返回 [key, value] 迭代器
const iterator1 = map1.entries(); // ["foo", "bar"]
console.log(iterator1.next().value); // ["foo", 3]

map 和 object 的区别

  • 键类型:map 可以是任意类型,object 只能是 string/symbol;
  • 键顺序:map 根据插入顺序排序,object 键无序;
  • 性能:map 具有更好的插入和删除性能,object 具有更好的查找性能;
  • size:map 可直接获取 size,object 只能通过 key/value 等方法计算;
  • 原型链:map 不存在原型链,object 可能因为原型链导致键被覆盖;

The WeakMap Type

WeakMap 基础

创建 WeakMap
const wm = new WeakMap();
// 初始化
// key 必须是一个 object
const key1 = { id: 1 };
key2 = { id: 2 };
key3 = { id: 3 };
const m1 = new WeakMap([
[key1, "val1"];
[key2, "val2"];
[key3, "val3"];
]);
key 类型约束原因
  • 保证 WeakMap 中的 value 只能通过 key 访问;
  • 如果使用字面量类型,访问 WeakMap 时,无法区别字面量是初始化时的字面量;

常用 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
拓展 set
const s = new Set(["val1", "val2", "val3"]);
console.log([...s]); // [val1,val2,val3]

常用 API

操作 set
const set1 = new Set();
// 添加键值对, 可链式使用
set1.add(42).add(13).add(42); // [42, 13]
// 判断是否具有 42
console.log(set1.has(42)); // true
// 删除大于 42 的值
set1.forEach((point) => {
if (point.x > 10) {
set1.delete(point);
}
});
// 清空 set
set1.clear();
迭代 Set
// Set 记录键值对的插入顺序;
// 并可根据插入顺序执行迭代操作;
const set1 = new Set([42, "forty two"]);
// 迭代 Set
map.forEach((element, index, map) => {
//..;
}, this);
// 返回 values 迭代器
const iterator1 = map1.values(); // [42, "forty two"]
console.log(iterator1.next().value); // 42
// values() 的别名
const iterator1 = map1.keys(); // [42, "forty two"]
console.log(iterator1.next().value); // 42
// 返回 [value, value] 迭代器
const iterator1 = set1.entries(); // [[42, 42], ["forty two", "forty two"]]
console.log(iterator1.next().value); // [42, 42]

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

// WeakSet key 为弱引用
// WeakSet 不会阻止作为 key 的 object 的回收
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

  • 由于 WeakSet 中的键值对可在任意时刻垃圾回收;
  • Iterable 不具有存在意义;
  • 进而导致无 clear(),keys(),values() 方法;

拓展运算符

具有 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;
  • 遍历 + include;
  • filter + indexOf;
  • set;
// 使用 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));

原型方法

和 [] 的 valueOf 和 toString
{}.valueOf // {}
{}.toString // [object Object]
[].valueOf // []
[].toString // ""

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]