一看就懂的JS手写函数(call、防抖节流)

简介: JS手写 call、防抖节流

call函数

先从改变this指向上简单实现一个方法添加到Function的原型链上:

Function.prototype.myCall = function (content) {
    content.fn = this
    const result = eval(`content.fn()`)
    return result
}

这就实现了call函数核心部分,因为使用了字符串的形式,所以函数的参数部分还需要进行特殊处理:

Function.prototype.myCall = function (content) {
    content.fn = this
    /** 处理参数 */
    const args = []
    for (let i = 1; i < arguments.length; i++) {
        args.push(`arguments[${i}]`) // 直接push会导致强转字符串时出现:[]
    }
    /** */
    const result = eval(`content.fn(${args})`)
    return result
}

基本可以了,但还有问题,临时属性的处理,最终优化结果:

Function.prototype.myCall = function (content) {
    const fn = `fn_${(Math.random()*999).toFixed()}` // 防止极端情况下属性名冲突
    content[fn] = this
    const args = []
    for (let i = 1; i < arguments.length; i++) {
        args.push(`arguments[${i}]`)
    }
    const result = eval(`content[fn](${args})`)
    delete content[fn] // 使用后释放
    return result
}

写个例子测试下:

const a = {
    name: 'a',
    say: function (t) { console.log(`${t}, ${this.name}`) }
}
const b = { name: 'b' }

a.say.call(b, 'hi') // hi, b
a.say.myCall(b, 'hello') // hello, b

防抖

以滚动事件为例,防抖即是滚动过程中低频率地触发事件

window.onscroll = debounce(function () {
    console.log('debounce'); // 持续滚动只会间隔1s有节奏地执行打印
}, 1000)

定时器 debounce 实现:

function debounce(fn, delay = 1000) {
    let timer = null;
    return function () {
        if (timer) {
            return
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments);
            timer = null; // 闭包,释放timer
        }, delay)
    }
}

时间戳 debounce 实现:

function debounce(fn, delayTime = 1000) {
    let lastTime = 0
    return function () {
        const nowTime = new Date().getTime()
        if (nowTime - lastTime > delayTime) {
            fn.call(this, ...arguments)
            lastTime = nowTime // 也是闭包,维护一个时间戳
        }
    }
}

节流

以滚动事件为例,节流即是滚动过程中只触发一次事件

window.onscroll = throttle(function () {
    console.log('throttle'); // 直到完全停止滚动后1s才执行输出
}, 1000)

定时器实现:

function throttle(fn, delay = 1000) {
    let timer = null
    return function () {
        if (timer) {
            clearTimeout(timer) // 与防抖的主要区别,前面的任务清除,只保留最后一次执行
        }
        timer = setTimeout(() => {
            fn.call(this, ...arguments)
            timer = null
        }, delay);
    }
}
相关文章
|
3月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
122 19
|
5月前
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索
|
7月前
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
148 32
|
6月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
10月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
135 1
|
10月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
11月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
11月前
|
JavaScript 前端开发
JS高级—call(),apply(),bind()
【10月更文挑战第17天】call()`、`apply()`和`bind()`是 JavaScript 中非常重要的工具,它们为我们提供了灵活控制函数执行和`this`指向的能力。通过合理运用这些方法,可以实现更复杂的编程逻辑和功能,提升代码的质量和可维护性。你在实际开发中可以根据具体需求,选择合适的方法来满足业务需求,并不断探索它们的更多应用场景。
80 1
|
11月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
11月前
|
前端开发 JavaScript UED
JavaScript 中的函数防抖与节流详解及实用场景
在前端开发中,处理用户频繁触发的事件,如输入框的输入、按钮点击、窗口调整大小等,常常需要优化性能以减少无效操作。为此,函数防抖(debounce)和函数节流(throttle)是两种常见的性能优化手段。本文将详细介绍两者的区别与实现,并探讨它们的应用场景。
300 1