一看就懂的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);
    }
}
相关文章
|
1月前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
43 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
1月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
27 1
|
1月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
2月前
|
JavaScript 前端开发
JS高级—call(),apply(),bind()
【10月更文挑战第17天】call()`、`apply()`和`bind()`是 JavaScript 中非常重要的工具,它们为我们提供了灵活控制函数执行和`this`指向的能力。通过合理运用这些方法,可以实现更复杂的编程逻辑和功能,提升代码的质量和可维护性。你在实际开发中可以根据具体需求,选择合适的方法来满足业务需求,并不断探索它们的更多应用场景。
14 1
|
2月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
2月前
|
前端开发 JavaScript UED
JavaScript 中的函数防抖与节流详解及实用场景
在前端开发中,处理用户频繁触发的事件,如输入框的输入、按钮点击、窗口调整大小等,常常需要优化性能以减少无效操作。为此,函数防抖(debounce)和函数节流(throttle)是两种常见的性能优化手段。本文将详细介绍两者的区别与实现,并探讨它们的应用场景。
48 1
|
2月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
48 4
|
2月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
23 2
|
2月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
26 3