节流和防抖
const debounce = (fn, time) => {
let timer
return () => {
if(timer){
clearTimeout(timer)
}
timer = setTime(fn, time)
}
}
const throttle = (fn, time) => {
let prev = 0
return () => {
const now = Date.now()
if(now - prev >= time){
fn()
prev = now
}
}
}
//debounce.js
/**
* @param {*} fn 要执行的函数
* @param {*} delay 延迟时间
* @param {*} immediate 是否立即执行
* @returns
*/
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null;
let isInvoke = false; //记录立即执行是否已执行过
// 2.真正执行的函数
const _debounce = function (...args) {
// 取消上一次的定时器
if (timer) clearTimeout(timer);
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, args);
isInvoke = true;
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args);
//没有这个步骤时,只有第一次输入是立即执行,即使后面延迟执行后再输入也是延迟执行;
// 有这个步骤时,第一次输入时立即执行,后面延迟执行后再输入也会有立即执行
isInvoke = false
timer = null
}, delay);
}
};
return _debounce;
}
function myThrottle(fn, interval, immediate = true){
let startTime = 0
const _throttle = function(...args){
const nowTime = new Date().getTime()
if(!immediate && startTime === 0){
startTime = nowTime
}
const waitTime = interval - (nowTime - startTime)
if(waitTime <= 0){
fn.apply(this,args)
startTime = nowTime
}
}
return _throttle
}
函数柯理化
const curry = (fn) =>
curried = (...args) =>
args.length >= fn.length
? fn(...args)
: (...nextArgs) => curried(...args, ...nextArgs);
// 结合 compose 或 pipe 实现复杂逻辑
// 组合多个函数
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
// 柯里化处理数据流
const toUpperCase = str => str.toUpperCase();
const exclaim = str => str + '!';
const emphasize = compose(curry(exclaim), curry(toUpperCase));
class转es5
手写instanceof
function myInstanceof(source, ctor) {
/** 判断非引用类型 */
if (!["function", "object"].includes(typeof source) || source === null) return false
/** 查找原型链 */
let proto = Object.getPrototypeOf(source)
while (true) {
if (proto === null) return false
if (proto === ctor.prototype) return true
proto = Object.getPrototypeOf(proto)
}
}
手写call、bind
Function.prototype.myCall = function (ctx, ...args) {
// 参数归一化
ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx)
// 拿到要执行的函数
const fn = this
// 绑定函数到ctx,(优化:不能被遍历到)
const key = Symbol("function_call")
Object.defineProperty(ctx, key, {
value: fn,
enumerable: false,
})
// 执行函数并返回对应的结果
const result = ctx[key](...args)
delete ctx[key]
return result
}
function test(a, b) {
console.log(this, a, b, this.name)
return a + b
}
console.log(test.myCall({ name: "tttt" }, 1, 3))
Function.prototype.myBind = function (ctx, ...args) {
// 要执行的函数
const fn = this
return function A(...rest) {
// 如果是 new 调用的,保留new的行为
if (Object.getPrototypeOf(this) === A.prototype) {
// 或者 this instanceof A
return new fn(...args, ...rest)
}
// 执行函数并返回结果
return fn.apply(ctx, [...args, ...rest])
}
}
function test(a, b, c, d) {
console.log(this, a, b, c, d)
return a + b
}
const newFn = test.myBind({ name: "aa" }, 1, 2)
console.log(newFn(3, 4))
console.log(new newFn(3, 4))
手写深拷贝
function deepClone(obj) {
// 如果是 值类型 或 null,则直接return
if(typeof obj !== 'object' || obj === null) {
return obj
}
// 定义结果对象
let copy = {}
// 如果对象是数组,则定义结果数组
if(obj instanceof Array) {
copy = []
}
// 遍历对象的key
for(let key in obj) {
// 如果key是对象的自有属性
if(obj.hasOwnProperty(key)) {
// 递归调用深拷贝方法
copy[key] = deepClone(obj[key])
}
}
return copy
}