集合引用类型
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; // 读取字节长度
类型
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) |
常用 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
类型
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
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]