Call the function

Add a simple method to the prototype chain of Function by changing the direction of this:

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

This implements the core part of the call function, which requires special handling of the argument part of the function because of the string form:

Function.prototype.myCall = function (content) {
    content.fn = this
    /** Handle arguments */
    const args = []
    for (let i = 1; i < arguments.length; i++) {
        args.push(`arguments[${i}] `) // Direct push causes strong string translations :[]
    }
    / * * * /
    const result = eval(`content.fn(${args}) `)
    return result
}
Copy the code

It is basically ok, but there are still problems, temporary attribute processing, final optimization result:

Function.prototype.myCall = function (content) {
    const fn = `fn_The ${(Math.random()*999).toFixed()}` // Prevent attribute name conflicts in extreme cases
    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] // Release after use
    return result
}
Copy the code

Write an example to test:

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

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

Image stabilization

Take the rolling event as an example, shaking prevention is triggered at a low frequency in the rolling process

window.onscroll = throttle(function () {
    console.log('throttle'); // Continuous scrolling only rhythmically prints 1s apart
}, 1000)
Copy the code

Timer throttle implementation:

function throttle(fn, delay = 1000) {
    let timer = null;
    return function () {
        if (timer) {
            return
        }
        timer = setTimeout(() = > {
            fn.apply(this.arguments);
            timer = null; // Release the timer
        }, delay)
    }
}
Copy the code

Timestamp throttle implementation:

function throttle(fn, delayTime = 1000) {
    let lastTime = 0
    return function () {
        const nowTime = new Date().getTime()
        if (nowTime - lastTime > delayTime) {
            fn.call(this. arguments) lastTime = nowTime// Also a closure that maintains a timestamp}}}Copy the code

The throttle

Again, using the rolling event as an example, throttling means that only one event is triggered during the rolling process

window.onscroll = debounce(function () {
    console.log('debounce'); // The output is not executed until 1s after the scroll has completely stopped
}, 1000)
Copy the code

The timer debounce implementation is the same as the anti-shock implementation, the difference is that the throttle is not executed multiple times:

function debounce(fn, delay = 1000) {
    let timer = null
    return function () {
        if (timer) {
            clearTimeout(timer) // The main difference with anti-shake is that the previous task is cleared and only reserved for the last execution
        }
        timer = setTimeout(() = > {
            fn.call(this. arguments) timer =null}, delay); }}Copy the code