@zhouyihang/js-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +64 -0
  2. package/package.json +45 -0
  3. package/src/algorithms/index.js +16 -0
  4. package/src/algorithms/myAtoi.js +19 -0
  5. package/src/algorithms/removeDuplicateLetters.js +29 -0
  6. package/src/algorithms/removeKdigits.js +25 -0
  7. package/src/algorithms/sort.js +117 -0
  8. package/src/algorithms/threeSum.js +34 -0
  9. package/src/algorithms/twoSum.js +23 -0
  10. package/src/algorithms/validParentheses.js +22 -0
  11. package/src/algorithms/wordDictionary.js +27 -0
  12. package/src/data-structures/index.js +1 -0
  13. package/src/data-structures/queue.js +46 -0
  14. package/src/dom/index.js +1 -0
  15. package/src/dom/traverseEl.js +19 -0
  16. package/src/framework/hashRouter.js +25 -0
  17. package/src/framework/historyRouter.js +35 -0
  18. package/src/framework/index.js +4 -0
  19. package/src/framework/reactive.js +56 -0
  20. package/src/framework/vdom.js +37 -0
  21. package/src/index.js +66 -0
  22. package/src/javascript/curry.js +8 -0
  23. package/src/javascript/index.js +2 -0
  24. package/src/javascript/inheritance.js +23 -0
  25. package/src/patterns/index.js +3 -0
  26. package/src/patterns/proxyObserver.js +30 -0
  27. package/src/patterns/pubsub.js +30 -0
  28. package/src/patterns/singleton.js +32 -0
  29. package/src/polyfills/call.js +54 -0
  30. package/src/polyfills/deepClone.js +36 -0
  31. package/src/polyfills/deepFreeze.js +11 -0
  32. package/src/polyfills/index.js +8 -0
  33. package/src/polyfills/iterator.js +13 -0
  34. package/src/polyfills/jsonStringify.js +27 -0
  35. package/src/polyfills/new.js +7 -0
  36. package/src/polyfills/promise.js +99 -0
  37. package/src/polyfills/promiseMethods.js +67 -0
  38. package/src/types/index.d.ts +1 -0
  39. package/src/types/nestedArray.d.ts +3 -0
  40. package/src/utils/asyncPool.js +21 -0
  41. package/src/utils/chunkArr.js +10 -0
  42. package/src/utils/debounce.js +11 -0
  43. package/src/utils/flatten.js +40 -0
  44. package/src/utils/formatSizeUnits.js +13 -0
  45. package/src/utils/index.js +10 -0
  46. package/src/utils/makeTree.js +17 -0
  47. package/src/utils/mergeArr.js +18 -0
  48. package/src/utils/parseUrl.js +13 -0
  49. package/src/utils/throttle.js +14 -0
  50. package/src/utils/toTree.js +23 -0
package/src/index.js ADDED
@@ -0,0 +1,66 @@
1
+ // ========== Polyfills (手写系列) ==========
2
+ export {
3
+ myCall,
4
+ myApply,
5
+ myBind,
6
+ applyPolyfills,
7
+ myNew,
8
+ deepClone,
9
+ deepFreeze,
10
+ jsonStringify,
11
+ MyPromise,
12
+ promiseAll,
13
+ promiseRace,
14
+ promiseAllSettled,
15
+ promiseAny,
16
+ createIterator,
17
+ } from "./polyfills/index.js";
18
+
19
+ // ========== Utility Functions (工具函数) ==========
20
+ export {
21
+ debounce,
22
+ throttle,
23
+ flatten,
24
+ flattenReduce,
25
+ flattenDeep,
26
+ mergeArr,
27
+ chunkArr,
28
+ formatSizeUnits,
29
+ parseUrl,
30
+ makeTree,
31
+ toTree,
32
+ asyncPool,
33
+ } from "./utils/index.js";
34
+
35
+ // ========== Design Patterns (设计模式) ==========
36
+ export { Singleton, Storage, PubSub, createProxyObj } from "./patterns/index.js";
37
+
38
+ // ========== Framework Internals (框架原理) ==========
39
+ export { reactive, effect, h, mount, HashRouter, HistoryRouter } from "./framework/index.js";
40
+
41
+ // ========== Algorithms (算法) ==========
42
+ export {
43
+ twoSum,
44
+ threeSum,
45
+ myAtoi,
46
+ WordDictionary,
47
+ removeDuplicateLetters,
48
+ removeKdigits,
49
+ validParentheses,
50
+ quickSort,
51
+ insertionSort,
52
+ selectionSort,
53
+ bubbleSort,
54
+ shellSort,
55
+ mergeSort,
56
+ countingSort,
57
+ } from "./algorithms/index.js";
58
+
59
+ // ========== Data Structures (数据结构) ==========
60
+ export { Queue } from "./data-structures/index.js";
61
+
62
+ // ========== DOM Utilities ==========
63
+ export { traverseElRoot } from "./dom/index.js";
64
+
65
+ // ========== JavaScript Basics (JS基础) ==========
66
+ export { curry, inherit } from "./javascript/index.js";
@@ -0,0 +1,8 @@
1
+ function curry(fn, ...args) {
2
+ if (args.length >= fn.length) {
3
+ return fn(...args);
4
+ }
5
+ return (..._args) => curry(fn, ...args, ..._args);
6
+ }
7
+
8
+ export default curry;
@@ -0,0 +1,2 @@
1
+ export { default as curry } from "./curry.js";
2
+ export { inherit, Parent, Child } from "./inheritance.js";
@@ -0,0 +1,23 @@
1
+ // 寄生组合继承
2
+ function inherit(Child, Parent) {
3
+ Child.prototype = Object.create(Parent.prototype);
4
+ Child.prototype.constructor = Child;
5
+ }
6
+
7
+ // 示例
8
+ function Parent(name) {
9
+ this.name = name;
10
+ }
11
+
12
+ Parent.prototype.sayHello = function () {
13
+ return "Hello " + this.name;
14
+ };
15
+
16
+ function Child(name, age) {
17
+ Parent.call(this, name);
18
+ this.age = age;
19
+ }
20
+
21
+ inherit(Child, Parent);
22
+
23
+ export { inherit, Parent, Child };
@@ -0,0 +1,3 @@
1
+ export { Singleton, Storage } from "./singleton.js";
2
+ export { default as PubSub } from "./pubsub.js";
3
+ export { createProxyObj } from "./proxyObserver.js";
@@ -0,0 +1,30 @@
1
+ import PubSub from "./pubsub.js";
2
+
3
+ function createProxyObj(obj, option = {}) {
4
+ const observer = new PubSub();
5
+ const handler = {
6
+ get(target, key) {
7
+ return target[key];
8
+ },
9
+ set(target, key, value) {
10
+ target[key] = value;
11
+ observer.$emit("change", key, value);
12
+ return true;
13
+ },
14
+ };
15
+
16
+ const proxy = new Proxy(obj, handler);
17
+ proxy.$on = observer.$on.bind(observer);
18
+ proxy.$off = observer.$off.bind(observer);
19
+ proxy.$emit = observer.$emit.bind(observer);
20
+
21
+ for (const key in option) {
22
+ if (!proxy[key]) {
23
+ proxy[key] = option[key];
24
+ }
25
+ }
26
+
27
+ return proxy;
28
+ }
29
+
30
+ export { createProxyObj };
@@ -0,0 +1,30 @@
1
+ class PubSub {
2
+ constructor() {
3
+ this.events = {};
4
+ }
5
+
6
+ $on(name, callback) {
7
+ if (!this.events[name]) {
8
+ this.events[name] = [];
9
+ }
10
+ this.events[name].push(callback);
11
+ }
12
+
13
+ $off(name, callback) {
14
+ if (!this.events[name]) return;
15
+ if (!callback) {
16
+ this.events[name] = undefined;
17
+ return;
18
+ }
19
+ this.events[name] = this.events[name].filter((item) => item !== callback);
20
+ }
21
+
22
+ $emit(name, ...args) {
23
+ if (!this.events[name]) return;
24
+ this.events[name].forEach((callback) => {
25
+ callback(...args);
26
+ });
27
+ }
28
+ }
29
+
30
+ export default PubSub;
@@ -0,0 +1,32 @@
1
+ class Singleton {
2
+ constructor(implClass) {
3
+ this.implClass = implClass;
4
+ }
5
+
6
+ getInstance(...args) {
7
+ if (!this.instance) {
8
+ this.instance = new this.implClass(...args);
9
+ }
10
+ return this.instance;
11
+ }
12
+ }
13
+
14
+ // Storage 单例示例
15
+ class Storage {
16
+ static getInstance() {
17
+ if (!Storage.instance) {
18
+ Storage.instance = new Storage();
19
+ }
20
+ return Storage.instance;
21
+ }
22
+
23
+ setItem(key, value) {
24
+ return localStorage.setItem(key, value);
25
+ }
26
+
27
+ getItem(key) {
28
+ return localStorage.getItem(key);
29
+ }
30
+ }
31
+
32
+ export { Singleton, Storage };
@@ -0,0 +1,54 @@
1
+ function myCall(fn, context, ...args) {
2
+ if (typeof fn !== "function") {
3
+ throw new TypeError("被调用的对象必须是函数");
4
+ }
5
+ context = context || globalThis;
6
+ const key = Symbol("fn");
7
+ context[key] = fn;
8
+ const result = context[key](...args);
9
+ delete context[key];
10
+ return result;
11
+ }
12
+
13
+ function myApply(fn, context, argsArr) {
14
+ if (typeof fn !== "function") {
15
+ throw new TypeError("被调用的对象必须是函数");
16
+ }
17
+ if (argsArr && !Array.isArray(argsArr)) {
18
+ throw new TypeError("第二个参数必须是数组");
19
+ }
20
+ context = context || globalThis;
21
+ const key = Symbol("fn");
22
+ context[key] = fn;
23
+ const result = context[key](...argsArr);
24
+ delete context[key];
25
+ return result;
26
+ }
27
+
28
+ function myBind(fn, context, ...args) {
29
+ if (typeof fn !== "function") {
30
+ throw new TypeError("被绑定的对象必须是函数");
31
+ }
32
+ context = context || globalThis;
33
+ return function bound(...innerArgs) {
34
+ if (this instanceof bound) {
35
+ return new fn(...args, ...innerArgs);
36
+ }
37
+ return fn.apply(context, args.concat(innerArgs));
38
+ };
39
+ }
40
+
41
+ // opt-in: 挂载到 Function.prototype
42
+ function applyPolyfills() {
43
+ Function.prototype.myCall = function (context, ...args) {
44
+ return myCall(this, context, ...args);
45
+ };
46
+ Function.prototype.myApply = function (context, argsArr) {
47
+ return myApply(this, context, argsArr);
48
+ };
49
+ Function.prototype.myBind = function (context, ...args) {
50
+ return myBind(this, context, ...args);
51
+ };
52
+ }
53
+
54
+ export { myCall, myApply, myBind, applyPolyfills };
@@ -0,0 +1,36 @@
1
+ function deepClone(obj, map = new Map()) {
2
+ if (typeof obj !== "object" || obj === null) {
3
+ return obj;
4
+ }
5
+ if (map.has(obj)) {
6
+ return map.get(obj);
7
+ }
8
+
9
+ let newObj;
10
+ if (Array.isArray(obj)) {
11
+ newObj = [];
12
+ } else if (obj instanceof Date) {
13
+ newObj = new Date(obj);
14
+ } else if (obj instanceof RegExp) {
15
+ newObj = new RegExp(obj.source, obj.flags);
16
+ } else {
17
+ newObj = {};
18
+ }
19
+
20
+ map.set(obj, newObj);
21
+
22
+ for (let key in obj) {
23
+ if (obj.hasOwnProperty(key)) {
24
+ newObj[key] = deepClone(obj[key], map);
25
+ }
26
+ }
27
+
28
+ const symbolKeys = Object.getOwnPropertySymbols(obj);
29
+ for (const symbol of symbolKeys) {
30
+ newObj[symbol] = deepClone(obj[symbol], map);
31
+ }
32
+
33
+ return newObj;
34
+ }
35
+
36
+ export default deepClone;
@@ -0,0 +1,11 @@
1
+ function deepFreeze(obj) {
2
+ Object.freeze(obj);
3
+ for (let key in obj) {
4
+ if (typeof obj[key] === "object" && !Object.isFrozen(obj[key])) {
5
+ deepFreeze(obj[key]);
6
+ }
7
+ }
8
+ return obj;
9
+ }
10
+
11
+ export default deepFreeze;
@@ -0,0 +1,8 @@
1
+ export { myCall, myApply, myBind, applyPolyfills } from "./call.js";
2
+ export { default as myNew } from "./new.js";
3
+ export { default as deepClone } from "./deepClone.js";
4
+ export { default as deepFreeze } from "./deepFreeze.js";
5
+ export { default as jsonStringify } from "./jsonStringify.js";
6
+ export { default as MyPromise } from "./promise.js";
7
+ export { promiseAll, promiseRace, promiseAllSettled, promiseAny } from "./promiseMethods.js";
8
+ export { default as createIterator } from "./iterator.js";
@@ -0,0 +1,13 @@
1
+ function createIterator(list) {
2
+ let index = 0;
3
+ const length = list.length;
4
+ return {
5
+ next: () => {
6
+ const done = index >= length;
7
+ const value = !done ? list[index++] : undefined;
8
+ return { done, value };
9
+ },
10
+ };
11
+ }
12
+
13
+ export default createIterator;
@@ -0,0 +1,27 @@
1
+ function jsonStringify(target) {
2
+ let type = typeof target;
3
+ if (type !== "object") {
4
+ if (/string|undefined|function/.test(type)) {
5
+ target = '"' + target + '"';
6
+ }
7
+ return String(target);
8
+ }
9
+
10
+ let json = [];
11
+ let arr = target && target.constructor === Array;
12
+
13
+ for (let k in target) {
14
+ let v = target[k];
15
+ let vType = typeof v;
16
+ if (/string|undefined|function/.test(vType)) {
17
+ v = '"' + v + '"';
18
+ } else if (vType === "object") {
19
+ v = jsonStringify(v);
20
+ }
21
+ json.push((arr ? "" : '"' + k + '":') + String(v));
22
+ }
23
+
24
+ return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
25
+ }
26
+
27
+ export default jsonStringify;
@@ -0,0 +1,7 @@
1
+ function myNew(Fn, ...args) {
2
+ const obj = Object.create(Fn.prototype);
3
+ const result = Fn.apply(obj, args);
4
+ return result instanceof Object ? result : obj;
5
+ }
6
+
7
+ export default myNew;
@@ -0,0 +1,99 @@
1
+ class MyPromise {
2
+ constructor(executor) {
3
+ this.state = "pending";
4
+ this.value = undefined;
5
+ this.reason = undefined;
6
+ this.onFulfilledCallbacks = [];
7
+ this.onRejectedCallbacks = [];
8
+
9
+ const resolve = (value) => {
10
+ if (this.state === "pending") {
11
+ this.state = "fulfilled";
12
+ this.value = value;
13
+ this.onFulfilledCallbacks.forEach((fn) => fn());
14
+ }
15
+ };
16
+
17
+ const reject = (reason) => {
18
+ if (this.state === "pending") {
19
+ this.state = "rejected";
20
+ this.reason = reason;
21
+ this.onRejectedCallbacks.forEach((fn) => fn());
22
+ }
23
+ };
24
+
25
+ try {
26
+ executor(resolve, reject);
27
+ } catch (e) {
28
+ reject(e);
29
+ }
30
+ }
31
+
32
+ then(onFulfilled, onRejected) {
33
+ onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
34
+ onRejected =
35
+ typeof onRejected === "function"
36
+ ? onRejected
37
+ : (e) => {
38
+ throw e;
39
+ };
40
+
41
+ return new MyPromise((resolve, reject) => {
42
+ const handleFulfilled = () => {
43
+ queueMicrotask(() => {
44
+ try {
45
+ const result = onFulfilled(this.value);
46
+ resolve(result);
47
+ } catch (e) {
48
+ reject(e);
49
+ }
50
+ });
51
+ };
52
+
53
+ const handleRejected = () => {
54
+ queueMicrotask(() => {
55
+ try {
56
+ const result = onRejected(this.reason);
57
+ resolve(result);
58
+ } catch (e) {
59
+ reject(e);
60
+ }
61
+ });
62
+ };
63
+
64
+ if (this.state === "fulfilled") {
65
+ handleFulfilled();
66
+ } else if (this.state === "rejected") {
67
+ handleRejected();
68
+ } else {
69
+ this.onFulfilledCallbacks.push(handleFulfilled);
70
+ this.onRejectedCallbacks.push(handleRejected);
71
+ }
72
+ });
73
+ }
74
+
75
+ catch(onRejected) {
76
+ return this.then(null, onRejected);
77
+ }
78
+
79
+ finally(onFinally) {
80
+ return this.then(
81
+ (value) => MyPromise.resolve(onFinally()).then(() => value),
82
+ (reason) =>
83
+ MyPromise.resolve(onFinally()).then(() => {
84
+ throw reason;
85
+ })
86
+ );
87
+ }
88
+
89
+ static resolve(value) {
90
+ if (value instanceof MyPromise) return value;
91
+ return new MyPromise((resolve) => resolve(value));
92
+ }
93
+
94
+ static reject(reason) {
95
+ return new MyPromise((_, reject) => reject(reason));
96
+ }
97
+ }
98
+
99
+ export default MyPromise;
@@ -0,0 +1,67 @@
1
+ function promiseAll(promises) {
2
+ return new Promise((resolve, reject) => {
3
+ const result = [];
4
+ let count = 0;
5
+ promises.forEach((promise, index) => {
6
+ Promise.resolve(promise).then(
7
+ (value) => {
8
+ result[index] = value;
9
+ count++;
10
+ if (count === promises.length) {
11
+ resolve(result);
12
+ }
13
+ },
14
+ (reason) => {
15
+ reject(reason);
16
+ }
17
+ );
18
+ });
19
+ });
20
+ }
21
+
22
+ function promiseRace(promises) {
23
+ return new Promise((resolve, reject) => {
24
+ promises.forEach((promise) => {
25
+ Promise.resolve(promise).then(resolve, reject);
26
+ });
27
+ });
28
+ }
29
+
30
+ function promiseAllSettled(promises) {
31
+ return new Promise((resolve) => {
32
+ const result = [];
33
+ let count = 0;
34
+ promises.forEach((promise, index) => {
35
+ Promise.resolve(promise).then(
36
+ (value) => {
37
+ result[index] = { status: "fulfilled", value };
38
+ count++;
39
+ if (count === promises.length) resolve(result);
40
+ },
41
+ (reason) => {
42
+ result[index] = { status: "rejected", reason };
43
+ count++;
44
+ if (count === promises.length) resolve(result);
45
+ }
46
+ );
47
+ });
48
+ });
49
+ }
50
+
51
+ function promiseAny(promises) {
52
+ return new Promise((resolve, reject) => {
53
+ const errors = [];
54
+ let count = 0;
55
+ promises.forEach((promise, index) => {
56
+ Promise.resolve(promise).then(resolve, (reason) => {
57
+ errors[index] = reason;
58
+ count++;
59
+ if (count === promises.length) {
60
+ reject(new AggregateError(errors, "All promises were rejected"));
61
+ }
62
+ });
63
+ });
64
+ });
65
+ }
66
+
67
+ export { promiseAll, promiseRace, promiseAllSettled, promiseAny };
@@ -0,0 +1 @@
1
+ export type { NestedArray } from "./nestedArray.js";
@@ -0,0 +1,3 @@
1
+ type NestedArray<T> = T | NestedArray<T>[];
2
+
3
+ export { NestedArray };
@@ -0,0 +1,21 @@
1
+ async function asyncPool(poolLimit, array, iteratorFn) {
2
+ const ret = [];
3
+ const pool = [];
4
+
5
+ for (const item of array) {
6
+ const p = Promise.resolve().then(() => iteratorFn(item));
7
+ ret.push(p);
8
+
9
+ if (poolLimit <= array.length) {
10
+ const e = p.then(() => pool.splice(pool.indexOf(e), 1));
11
+ pool.push(e);
12
+ if (pool.length >= poolLimit) {
13
+ await Promise.race(pool);
14
+ }
15
+ }
16
+ }
17
+
18
+ return Promise.all(ret);
19
+ }
20
+
21
+ export default asyncPool;
@@ -0,0 +1,10 @@
1
+ // chunk(["a", "b", "c", "d"], 2) => [["a", "b"], ["c", "d"]]
2
+ function chunkArr(array, size) {
3
+ const result = [];
4
+ for (let i = 0; i < array.length; i += size) {
5
+ result.push(array.slice(i, i + size));
6
+ }
7
+ return result;
8
+ }
9
+
10
+ export default chunkArr;
@@ -0,0 +1,11 @@
1
+ function debounce(func, delay) {
2
+ let timer;
3
+ return function (...args) {
4
+ clearTimeout(timer);
5
+ timer = setTimeout(() => {
6
+ func.apply(this, args);
7
+ }, delay);
8
+ };
9
+ }
10
+
11
+ export default debounce;
@@ -0,0 +1,40 @@
1
+ // 递归版本(支持指定深度)
2
+ function flatten(arr, level = 1) {
3
+ let result = [];
4
+ for (let i = 0; i < arr.length; i++) {
5
+ if (Array.isArray(arr[i]) && level > 0) {
6
+ result = result.concat(flatten(arr[i], level - 1));
7
+ } else {
8
+ result.push(arr[i]);
9
+ }
10
+ }
11
+ return result;
12
+ }
13
+
14
+ // reduce 版本
15
+ function flattenReduce(arr, level = 1) {
16
+ return arr.reduce(
17
+ (prev, cur) =>
18
+ prev.concat(
19
+ level > 0 && Array.isArray(cur) ? flattenReduce(cur, level - 1) : cur
20
+ ),
21
+ []
22
+ );
23
+ }
24
+
25
+ // 栈版本(完全扁平化)
26
+ function flattenDeep(arr) {
27
+ const stack = [...arr];
28
+ const res = [];
29
+ while (stack.length) {
30
+ const next = stack.pop();
31
+ if (Array.isArray(next)) {
32
+ stack.push(...next);
33
+ } else {
34
+ res.push(next);
35
+ }
36
+ }
37
+ return res.reverse();
38
+ }
39
+
40
+ export { flatten, flattenReduce, flattenDeep };
@@ -0,0 +1,13 @@
1
+ function formatSizeUnits(kb) {
2
+ const units = ["KB", "MB", "GB", "TB", "PB"];
3
+ let unitIndex = 0;
4
+
5
+ while (kb >= 1024 && unitIndex < units.length - 1) {
6
+ kb /= 1024;
7
+ unitIndex++;
8
+ }
9
+
10
+ return `${kb.toFixed(2)} ${units[unitIndex]}`;
11
+ }
12
+
13
+ export default formatSizeUnits;
@@ -0,0 +1,10 @@
1
+ export { default as debounce } from "./debounce.js";
2
+ export { default as throttle } from "./throttle.js";
3
+ export { flatten, flattenReduce, flattenDeep } from "./flatten.js";
4
+ export { default as mergeArr } from "./mergeArr.js";
5
+ export { default as chunkArr } from "./chunkArr.js";
6
+ export { default as formatSizeUnits } from "./formatSizeUnits.js";
7
+ export { default as parseUrl } from "./parseUrl.js";
8
+ export { default as makeTree } from "./makeTree.js";
9
+ export { default as toTree } from "./toTree.js";
10
+ export { default as asyncPool } from "./asyncPool.js";
@@ -0,0 +1,17 @@
1
+ // 将多个文件路径生成树形结构
2
+ function makeTree(paths) {
3
+ const tree = {};
4
+ paths.forEach((path) => {
5
+ const pathArr = path.split("/");
6
+ let current = tree;
7
+ pathArr.forEach((dir) => {
8
+ if (!current[dir]) {
9
+ current[dir] = {};
10
+ }
11
+ current = current[dir];
12
+ });
13
+ });
14
+ return tree;
15
+ }
16
+
17
+ export default makeTree;