常见js面试题--手写节流,防抖,深拷贝

一、防抖debounce

  1. 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间
  2. 当事件密集触发时,函数的触发会被频繁的推迟
  3. 只有等待了一段时间也没有事件触发,才会真正的执行响应函数

应用场景

  1. 输入框中频繁的输入内容,搜索或者提交信息
  2. 频繁的点击按钮,触发某个事件
  3. 监听浏览器滚动事件,完成某些特定操作
  4. 用户缩放浏览器的resize事件

二、节流throttle

  1. 当事件触发时,会执行这个事件的响应函数
  2. 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数
  3. 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的

应用场景

  1. 监听页面的滚动事件
  2. 鼠标移动事件
  3. 用户频繁点击按钮操作
  4. 游戏中的一些设计

三、防抖函数实现

简易版

如果是一个一般的面试,你可以就写个简易版的能实现要求就行

function debounce(fn, delay = 500) {
    let timer = null
    const _debounce = function(...args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, delay);
    }
    return _debounce
}

加强版

  1. 添加是否立即执行(每个阶段开始时都先执行一次)
  2. 添加取消功能
  3. 处理返回值
function debounce(fn, delay = 500, immediate = false, callback = null) {
    let timer = null
    // 是否有立即执行过
    let isInvoke = false
    const _debounce = function (...args) {
        if (timer) clearTimeout(timer)
        if (immediate && !isInvoke) {
            const result = fn.apply(this, args)
            if (callback) callback(result)
            isInvoke = true
        } else {
            timer = setTimeout(() => {
                const result = fn.apply(this, args)
                if (callback) callback(result)
                isInvoke = false
            }, delay);
        }
    }
    // 取消功能
    _debounce.cancel = function() {
        if (timer) clearTimeout(timer)
    }
    return _debounce
}

四、节流函数实现

简易版

function throttle(fn, interval = 1000) {
    let lastTime = 0
    const _throttle = function(...args) {
        const nowTime = new Date().getTime()
        const remainTime = interval - (nowTime - lastTime)
        if (remainTime <= 0) {
            fn.apply(this, args)
            lastTime = nowTime
        }
        
    }
    return _throttle
}

加强版

// leading 第一次是否执行  trailing 尾部是否执行
function throttle(fn, interval = 1000, options = { leading: true, trailing: false, callback: null }) {
    const { leading, trailing, callback } = options
    let lastTime = 0
    let timer = null
    const _throttle = function(...args) {
        const nowTime = new Date().getTime()
        // 第一次是否执行判断
        if (!leading && !lastTime) lastTime = nowTime
        const remainTime = interval - (nowTime - lastTime)
        if (remainTime <= 0) {
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            const result = fn.apply(this, args)
            if (callback) callback(result)
            lastTime = nowTime
            return
        }

        // 尾部是否执行
        if (trailing && !timer) {
            timer = setTimeout(() => {
                timer = null
                lastTime = !leading ? 0 : new Date().getTime()
                const result = fn.apply(this, args)
                if (callback) callback(result)
            }, remainTime);
        }

        // 取消
        _throttle.cancel = function() {
            if (timer) clearTimeout(timer)
            timer = null
            lastTime = 0
        }
         
    }
    return _throttle
}

五、深拷贝实现

简易版

function deepClone(originValue) {
    const originValueType = typeof originValue
    if (originValueType === 'function') return originValue
    if (originValue === null || originValueType !== 'object') return originValue

    const newObject = Array.isArray(originValue) ? [] : {}
    for (const key in originValue) {
        newObject[key] = deepClone(originValue[key])
    }
    return newObject
}

加强版

  1. 添加Symbol为key,或者值的处理
  2. 添加set处理
  3. 添加Map处理
  4. 添加循环引用处理
function deepClone(originValue, map = new WeakMap()) {
    // Set类型处理
    if (originValue instanceof Set) return new Set([...originValue])
    // Map类型处理
    if (originValue instanceof Map) return new Map([...originValue])

    const originValueType = typeof originValue
    // Symbol处理 如果值是Symbol,重新创建一个Symbol
    if (originValueType === 'symbol') return Symbol(originValue.description)
    // 函数处理
    if (originValueType === 'function') return originValue
    // 非对象类型处理
    if (originValue === null || originValueType !== 'object') return originValue
    // 处理循环引用
    if (map.has(originValue)) return map.get(originValue)

    const newObject = Array.isArray(originValue) ? [] : {}
    // 处理循环引用
    map.set(originValue, newObject)

    for (const key in originValue) {
        newObject[key] = deepClone(originValue[key], map)
    }
    // 对key是Symbol的特殊处理
    const symbolKeys = Object.getOwnPropertySymbols(originValue)
    for (const sKey of symbolKeys) {
        newObject[sKey] = deepClone(originValue[sKey], map)
    }

    return newObject
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值