用setTimeout实现setInterval
function customSetInterval(callback: () => void, delay: number): () => void {
let timer;
const interval = () => {
callback();
timer = setTimeout(interval, delay)
}
timer = setTimeout(interval, delay)
return () => {
clearTimeout(timer)
}
}
const callback = () => console.log("Hello, world!");
const delay = 1000;
const clearIntervalFunc = customSetInterval(callback, delay);
var实现let
function demo() {
(function() {
var x = "Hello, world!";
console.log(x);
})();
try {
console.log(x);
} catch (error) {
console.error(error);
}
}
demo();
实现所有的TypeScript Utility Types
type Partial<T> = { [P in keyof T]?: T[P] };
type Required<T> = { [P in keyof T]-?: T[P] };
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
type NonNullable<T> = Exclude<T, null | undefined>;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
type OmitThisParameter<T> = T extends (this: any, ...args: infer A) => infer R ? (...args: A) => R : T;
防抖debounce
function debounce(func: (...args: any[]) => void, wait: number): (...args: any[]) => void {
let timeout: ReturnType<typeof setTimeout> | null = null;
return (...args: any[]) => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
func.apply(null, args);
}, wait);
};
}
节流throttle
function throttle(func: (...args: any[]) => void, limit: number): (...args: any[]) => void {
let lastCall = 0;
return (...args: any[]) => {
const now = Date.now();
if (now - lastCall >= limit) {
func.apply(null, args);
lastCall = now;
}
};
}
New
function customNew(constructorFn: Function, ...args: any[]): object {
const obj = Object.create(constructorFn.prototype);
const result = constructorFn.apply(obj, args);
return (typeof result === "object" && result !== null) ? result : obj;
}
function Person(name: string, age: number) {
this.name = name;
this.age = age;
}
const alice = customNew(Person, "Alice", 30) as Person;
console.log(alice.name);
console.log(alice.age);
数组去重
const uniqueArray = (arr: any[]) => {
return [...new Set(arr)]
}
const uniqueArray = (arr: any[]) => {
const result = [];
for (const item of arr) {
if (result.indexOf(item) === -1) {
result.push(item);
}
}
return result;
}
const uniqueArray = (arr: any[]) => {
return arr.filter((item, index) => {
return arr.indexOf(item) === index
})
}
console.log(uniqueArray([1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5]));
实现正则切分千分位
function formatThousands(n: number): string {
const reg = /\d{1,3}(?=(\d{3})+$)/g;
const num = n.toString();
const formattedNum = num.replace(reg, '$&,');
return formattedNum;
}
console.log(formatThousands(123456789));
console.log(formatThousands(1000000));
console.log(formatThousands(9876543210));
call
Function.prototype.myCall = function (thisArg: any, ...args: any[]): any {
const fn = this;
const uniqueKey = Symbol("uniqueKey");
thisArg[uniqueKey] = fn;
const result = thisArg[uniqueKey](...args);
delete thisArg[uniqueKey];
return result;
};
const obj = {
name: 'Alice'
}
function greet(greeting: string, punctuation: string) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
greet.myCall(obj, "Hello", "!");
apply
Function.prototype.myApply = function (thisArg: any, args: any[]): any {
const fn = this;
const uniqueKey = Symbol("uniqueKey");
thisArg[uniqueKey] = fn;
const result = thisArg[uniqueKey](...args);
delete thisArg[uniqueKey];
return result;
};
const obj = {
name: 'Alice'
}
function greet(greeting: string, punctuation: string) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
greet.myApply(obj, ["Hi", "!"]);
bind
Function.prototype.myBind = function (thisArg: any, ...args1: any[]): (...args2: any[]) => any {
const fn = this;
return function (...args2: any[]) {
return fn.myApply(thisArg, args1.concat(args2));
};
};
const obj = {
name: 'Alice'
}
function greet(greeting: string, punctuation: string) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const boundGreet = greet.myBind(obj, "Hey");
boundGreet("?");
深拷贝
function deepClone(obj: any, cache = new WeakMap()): any {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (cache.has(obj)) {
return cache.get(obj);
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Function) {
return function(...args: any[]) {
obj.apply(this, args)
}
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
if (obj instanceof Array) {
const clonedArr: any[] = [];
cache.set(obj, clonedArr);
for (let i = 0; i < obj.length; ++i) {
clonedArr[i] = deepClone(obj[i], cache);
}
return clonedArr;
}
const clonedObj: { [key: string]: any } = {};
cache.set(obj, clonedObj);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clonedObj[key] = deepClone(obj[key], cache);
}
}
return clonedObj;
}
const original: { [key: string]: any } = {
name: "Alice",
age: 30,
dateOfBirth: new Date("1993-01-01"),
preferences: {
color: "blue",
food: "pizza"
},
sum() {
console.log(this.name + '-' + this.age);
}
};
original.original = original
original.originalArr = [original, original]
const cloned = deepClone(original);
console.log(cloned);
柯里化
function curry(fn: (...args: any[]) => any): (...args: any[]) => any {
const arity = fn.length;
function curried(...args: any[]): any {
if (args.length >= arity) {
return fn.apply(null, args);
}
return (...restArgs: any[]) => curried.apply(null, args.concat(restArgs));
}
return curried;
}
function add(a: number, b: number, c: number): number {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3));
es5和es6继承
function AnimalES5(name: string) {
this.name = name;
}
AnimalES5.prototype.sayName = function () {
console.log("My name is " + this.name);
};
function DogES5(name: string, breed: string) {
AnimalES5.call(this, name);
this.breed = breed;
}
DogES5.prototype = Object.create(AnimalES5.prototype);
DogES5.prototype.constructor = DogES5;
DogES5.prototype.sayBreed = function () {
console.log("My breed is " + this.breed);
};
const dogES5 = new DogES5("Max", "Golden Retriever");
dogES5.sayName();
dogES5.sayBreed();
class AnimalES6 {
name: string;
constructor(name: string) {
this.name = name;
}
sayName() {
console.log("My name is " + this.name);
}
}
class DogES6 extends AnimalES6 {
breed: string;
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
sayBreed() {
console.log("My breed is " + this.breed);
}
}
const dogES6 = new DogES6("Max", "Golden Retriever");
dogES6.sayName();
dogES6.sayBreed();
instanceof
function myInstanceOf(target: any, constructorFunc: Function): boolean {
if (typeof target !== 'object' || target === null || typeof constructorFunc !== 'function') {
return false;
}
let targetProto = Object.getPrototypeOf(target);
const constructorProto = constructorFunc.prototype;
while (targetProto !== null) {
if (targetProto === constructorProto) {
return true;
}
targetProto = Object.getPrototypeOf(targetProto);
}
return false;
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
const dog = new Dog();
const cat = new Cat();
console.log(myInstanceOf(dog, Dog));
console.log(myInstanceOf(dog, Animal));
console.log(myInstanceOf(cat, Dog));
console.log(myInstanceOf(cat, Animal));
console.log(myInstanceOf(123, Number));
数组扁平化
function flattenArray(arr: any[]): any[] {
const result: any[] = [];
function processItem(item: any) {
if (Array.isArray(item)) {
item.forEach(processItem);
} else {
result.push(item);
}
}
arr.forEach(processItem);
return result;
}
const nestedArray = [1, [2, [3, 4], 5, [6, [7, 8]]], 9, 10];
console.log(flattenArray(nestedArray));
const nestedArray2 = [1, [2, 3], 4, [[5], 6, [7, [8, 9, [10]]]]];
console.log(flattenArray(nestedArray2));
对象扁平化
function flattenObject(obj: { [key: string]: any }, prefix = ""): { [key: string]: any } {
const flattened: { [key: string]: any } = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (typeof obj[key] === "object" && obj[key] !== null && !Array.isArray(obj[key])) {
Object.assign(flattened, flattenObject(obj[key], newKey));
} else {
flattened[newKey] = obj[key];
}
}
}
return flattened;
}
// 示例用法
const nestedObj = {
a: {
b: {
c: 1,
d: {
e: 2
}
},
f: 3
},
g: {
h: 4
}
};
const flattenedObj = flattenObject(nestedObj);
console.log(flattenedObj);
// 输出 { 'a.b.c': 1, 'a.b.d.e': 2, 'a.f': 3, 'g.h': 4 }
JSON.parse
const myJSONParse = (target) => {
return eval(`(${target})`)
}
// 测试用例
const jsonString = '{"name": "John", "age": 30, "city": "New York"}'
const parsedObject = myJSONParse(jsonString)
console.log(parsedObject)
EventEmitter事件触发器
class EventEmitter {
private events: Map<string, Array<(...args: any[]) => void>>;
constructor() {
this.events = new Map();
}
on(event: string, listener: (...args: any[]) => void): void {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)!.push(listener);
}
off(event: string, listener: (...args: any[]) => void): void {
const listeners = this.events.get(event);
if (listeners) {
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
}
}
emit(event: string, ...args: any[]): void {
const listeners = this.events.get(event);
if (listeners) {
listeners.forEach(listener => listener.apply(null, args));
}
}
once(event: string, listener: (...args: any[]) => void): void {
const wrappedListener = (...args: any[]) => {
listener.apply(null, args);
this.off(event, wrappedListener);
};
this.on(event, wrappedListener);
}
}
const eventEmitter = new EventEmitter();
function hello(name: string) {
console.log(`Hello, ${name}!`);
}
eventEmitter.on("greet", hello);
eventEmitter.emit("greet", "Alice");
eventEmitter.off("greet", hello);
eventEmitter.emit("greet", "Bob");
eventEmitter.once("welcome", hello);
eventEmitter.emit("welcome", "Carol");
eventEmitter.emit("welcome", "David");
async/await
function customAsync(generatorFn: (...args: any[]) => Generator) {
return function (...args: any[]) {
const generator = generatorFn.apply(null, args);
function handle(result: IteratorResult<any>): Promise<any> {
if (result.done) {
return Promise.resolve(result.value);
}
return Promise.resolve(result.value)
.then(value => handle(generator.next(value)))
.catch(error => handle(generator.throw!(error)));
}
return handle(generator.next());
};
}
function* myGenerator() {
const result1 = yield new Promise(resolve => setTimeout(() => resolve("First result"), 1000));
console.log(result1);
const result2 = yield new Promise(resolve => setTimeout(() => resolve("Second result"), 1000));
console.log(result2);
return "Done";
}
const myAsyncFunction = customAsync(myGenerator);
myAsyncFunction().then(result => console.log(result));
正则获取url params
function getUrlParams(url: string): Record<string, string> {
const params: Record<string, string> = {};
const regex = /[?&]([^=&#]+)=([^&#]*)/g;
let match: RegExpExecArray | null;
while ((match = regex.exec(url)) !== null) {
params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
return params;
}
const testUrl1 = 'https://www.example.com/test?name=John&age=30&city=New%20York';
const result1 = getUrlParams(testUrl1);
console.log(result1);
const testUrl2 = 'https://www.example.com/test?query=test&page=1&filter=active';
const result2 = getUrlParams(testUrl2);
console.log(result2);
jsonp
function jsonp(url: string, params: { [key: string]: any }, callbackName: string): Promise<any> {
return new Promise((resolve, reject) => {
(window as any)[callbackName] = (data: any) => {
delete (window as any)[callbackName];
document.body.removeChild(script);
resolve(data);
};
const queryString = Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
const finalUrl = `${url}?${queryString}&callback=${callbackName}`;
const script = document.createElement("script");
script.src = finalUrl;
script.onerror = () => reject(new Error("JSONP request failed"));
document.body.appendChild(script);
});
}
const url = "https://api.example.com/data";
const params = {
userId: 123,
accessToken: "abcdefgh"
};
const callbackName = "jsonpCallback";
jsonp(url, params, callbackName)
.then(data => console.log(data))
.catch(error => console.error(error));
JSON.stringify
function customJSONStringify(obj: any): string | undefined {
const seenObjects: any[] = [];
function stringify(value: any): string | undefined {
if (typeof value === "number" || typeof value === "boolean" || value === null) {
return String(value);
}
if (typeof value === "string") {
return `"${value}"`;
}
if (typeof value === "undefined" || typeof value === "function" || value instanceof Symbol) {
return undefined;
}
if (seenObjects.indexOf(value) !== -1) {
throw new TypeError("Converting circular structure to JSON");
}
seenObjects.push(value);
if (Array.isArray(value)) {
const arr = value.map(item => stringify(item) ?? "null");
return `[${arr.join(",")}]`;
}
const keys = Object.keys(value).filter(key => typeof value[key] !== "function" && typeof value[key] !== "undefined");
const keyValuePairs = keys.map(key => `"${key}":${stringify(value[key]) ?? "null"}`);
return `{${keyValuePairs.join(",")}}`;
}
return stringify(obj);
}
const obj = {
name: "Alice",
age: 30,
sayHello: function() {
console.log("Hello");
},
preferences: {
color: "blue",
food: "pizza"
}
};
console.log(customJSONStringify(obj));
Promise
// 定义Promise的三种状态常量
enum PromiseStatus {
Pending = "PENDING",
Fulfilled = "FULFILLED",
Rejected = "REJECTED"
}
class CustomPromise {
status: PromiseStatus
value: any
reason: any
onFulfilledCallbacks: Array<(...args: any[]) => void>
onRejectedCallbacks: Array<(...args: any[]) => void>
constructor(executor: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) {
this.status = PromiseStatus.Pending
this.value = null
this.reason = null
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value?: any) => {
if (this.status === PromiseStatus.Pending) {
this.status = PromiseStatus.Fulfilled
this.value = value
this.onFulfilledCallbacks.forEach(callback => callback())
}
}
const reject = (reason?: any) => {
if (this.status === PromiseStatus.Pending) {
this.status = PromiseStatus.Rejected
this.reason = reason
this.onRejectedCallbacks.forEach(callback => callback())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled?: (value: any) => any, onRejected?: (reason: any) => any): CustomPromise {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason
const promise = new CustomPromise((resolve, reject) => {
const handleFulfilled = () => {
try {
const result = onFulfilled!(this.value)
if (result === promise) {
throw new TypeError("Chaining cycle detected for promise")
}
if (result instanceof CustomPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
const handleRejected = () => {
try {
const result = onRejected!(this.reason)
if (result === promise) {
throw new TypeError("Chaining cycle detected for promise")
}
if (result instanceof CustomPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
if (this.status === PromiseStatus.Fulfilled) {
queueMicrotask(handleFulfilled)
} else if (this.status === PromiseStatus.Rejected) {
queueMicrotask(handleRejected)
} else {
this.onFulfilledCallbacks.push(() => queueMicrotask(handleFulfilled))
this.onRejectedCallbacks.push(() => queueMicrotask(handleRejected))
}
})
return promise
}
catch(onRejected?: (reason: any) => any): CustomPromise {
return this.then(undefined, onRejected)
}
}
写一个通用的方法来获取地址栏的某个参数对应的值,不能使用正则表达式
function getQueryParam(paramName) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(paramName);
}
const myParamValue = getQueryParam('myParam');
console.log(myParamValue);
// 方法二
function getQueryParam(paramName) {
var params = window.location.search.substr(1).split('&')
for (let i = 0
let keyValuePair = params[i].split('=')
if (keyValuePair[0] === paramName) {
return decodeURIComponent(keyValuePair[1])
}
}
return null
}
// 使用示例
const myParamValue = getQueryParam('myParam')
console.log(myParamValue)