比较函数
Object.is()
console.log(Object.is(0, -0)); // false
console.log(Object.is(NaN, NaN)); // true
Object.is()用来比较两个值是否相等
simpleEqual
export function simpleEqual(x: unknown, y: unknown): boolean {
if (x === y) {
return true;
} else {
return false;
}
}
console.log(isEqual(0, -0)); // true
console.log(isEqual(NaN, NaN)); // false
一般情况下通过全等判断就能解决相等问题,但是为了实现Object.is()的polyfill,需要对 0和-0 ,NaN和NaN 特殊处理
complicateEqual
export function complicateEqual(x: unknown, y: unknown): boolean {
if (x === y) {
// 比较 Infinity !== -Infinity 返回true,取反,返回false
return !(x === 0 && 1 / x !== 1 / (y as number));
} else {
// NaN=== NaN 返回false,取反,返回true
return !(x === x || y === y);
}
}
console.log(complicateEqual(0, -0)); // false
console.log(complicateEqual(NaN, NaN)); //true
objectEqual
function objectEqual(
a: Record<string, any> | null = {},
b: Record<string, any> | null = {}
): boolean {
// 处理 null
if (!a || !b) return a === b;
const aKeys = Object.keys(a).sort();
const bKeys = Object.keys(b).sort();
// 属性长度不相等
if (aKeys.length !== bKeys.length) {
return false;
}
return aKeys.every((key, i) => {
const aVal = a[key];
const bKey = bKeys[i];
// 因为排序过,同一位置键名不相等
if (bKey !== key) return false;
const bVal = b[key];
// 键值为null时
if (aVal == null || bVal == null) return aVal === bVal;
// 键值都为对象类型时
if (typeof aVal === "object" && typeof bVal === "object") {
return objectEqual(aVal, bVal);
}
// 最后一步可以根据需求采用不同逻辑
// return aVal === bVal
// return simpleEqual(aVal, bVal);
// return complicateEqual(aVal, bVal);
return String(aVal) === String(bVal);
});
}
console.log(objectEqual({ a: 1 }, { a: 1 })); // true
自定义对象类型的比较
防抖函数
延迟执行
/**
* 触发 debouncedFn,等待 wait 毫秒后, 执行 fn 函数,
* 如果在此期间又触发了 debouncedFn ,则重新开始等待 wait 毫秒
* 这样保证在wait 毫秒内仅执行一次 debouncedFn
*/
function debounce(fn: (...args: any[]) => any, wait = 0, thisArgs?: Object) {
let debounceId: any = null;
return (...args: any[]) => {
if (debounceId) {
globalThis.clearTimeout(debounceId);
}
debounceId = globalThis.setTimeout(() => {
fn.apply(thisArgs, args);
}, wait);
};
}
function test(msg: string) {
console.log("hello " + msg);
}
let debouncedFn = debounce(test, 2000);
let intervalId: any = null;
intervalId = setInterval(debouncedFn, 500, "world");
setTimeout(() => {
clearInterval(intervalId);
}, 2000);
立即执行
export function debounce(
fn: (...args: any[]) => any,
wait = 0,
immediate = false,
thisArgs?: Object
) {
let debounceId: any = null;
return (...args: any[]) => {
if (immediate) {
let callNow = !debounceId;
if (callNow) {
debounceId = globalThis.setTimeout(() => {
debounceId = null;
}, wait);
fn.apply(thisArgs, args);
}
} else {
if (debounceId) {
clearTimeout(debounceId);
}
debounceId = globalThis.setTimeout(() => {
fn.apply(thisArgs, args);
}, wait);
}
};
}
function test(msg: string) {
console.log("hello " + msg);
}
let debouncedFn = debounce(test, 2000, true);
let intervalId: any = null;
intervalId = setInterval(debouncedFn, 500, "world");
setTimeout(() => {
clearInterval(intervalId);
}, 2000);
事件绑定
export {};
interface EventListener {
(evt: Event): void;
}
interface EventListenerObject {
handleEvent(object: Event): void;
}
declare var window: any;
const addEvent = (() => {
if (window.addEventListener) {
return function (
el: Node,
eventName: string,
handler: EventListener | EventListenerObject
) {
el.addEventListener(eventName, handler);
};
} else if (window.attachEvent) {
return function (
el: any,
eventName: string,
handler: EventListener | EventListenerObject
) {
el.attachEvent("on" + eventName, handler);
};
} else {
return function (
el: any,
eventName: string,
handler: EventListener | EventListenerObject
) {
el["on" + eventName] = handler;
};
}
})();