Tear Front End JavaScript by Hand (Phase 1)

Posted by JayBlake on Thu, 03 Mar 2022 19:10:25 +0100

1. Anti-shake function (debounce)

Purpose: Prevent users from triggering events multiple times and wasting multiple requests

Principle: Callback is executed after an event triggers for n seconds; If triggered again within n seconds, the time is recounted;

const debounce = function(func,delay = 50){
    /*
    	func: Functions requiring anti-shake
    	awit: Time to wait, default is 50ms
    */
    let timer = 0;	//Create a timer id
    
    /* This is equivalent to a factory function:
       func functions that pass users in, plus anti-shake functions;
       Then go back
    */
    return function(...args){	// Expand parameters passed in when calling func
        if(timer){
            // If a timer exists, the function has been triggered one or more times but has not been executed
            clearTimeout(timer);	// Clear timer task
        }
        // Set the timer again, whether or not it exists
        timer = setTimeout( ()=>{	
            func.apply(this,args);	// Using the apply function, call the function yourself and record the timer id in the timer
        },delay);	// Set Delay
    }
}

2. throttle function

Purpose: Prevent users from triggering multiple times, causing multiple requests and wasting resources

Principle: Multiple triggers in a user's unit time, executed only once;

const throttle = function(func, unitTime=1000) {
    let lastTime = 0;	// Used to record the last trigger time
    return function(...args){
        let now = +new Date();
        
        // If it is outside the set time range
        if(now - lastTime > unitTime) {
            lastTime = now;		// Record the trigger time of the current valid trigger
            func.apply(args);
        }
    }
}

3. Handwritten call() function

To write the call() function, you must first know what it does

  1. Functions do their own calls
  2. Expand the scope of the function;
  3. If no arguments are passed, this of the default function points to window
// Implement on Prototype
Function.prototype.myCall = function(context=window , ...args){	// (third function implemented)
    let key = Symbol('key');	// Create a unique identity with symbols
    context[key] = this;	// Add a new property in the context that points to the calling function itself;
    
    let result = context[key](...args);	// Stores the result of calling a function (the first function is implemented)
    delete context[key];	// Delete Properties
    return result;	// Returns the result of the call
}
function func(a,b){
    console.log(`${this.nickname}is${a+b}`);
}

let newContext = {
    nickname:'zyzc',
    color:'red'
}

func.myCall(newContext,1,2);    // zyzcis3

// In fact, it can be understood as follows:
// It can be understood as follows:
let callFunc = Symbol('key');
let newContextAfterMyCall = {
    nickname:'zyzc',
    color:'red',
    [callFunc]:(function(a,b){
        console.log(`${this.nickname}is${a+b}`);
    })
}
newContextAfterMyCall[callFunc](1,2);
delete newContextAfterMyCall[callFunc];

4. Handwritten apply() function

In fact, apply() and call() are just different in receiving parameters

  • For apply(), the second parameter is an array of parameters
  • For call(), the second parameter starts with a parameter-by-parameter approach
// Implement on Prototype
Function.prototype.myCall = function(context=window , ...args){	
    let key = Symbol('key');	
    context[key] = this;
    
    // Just make a few changes here
    let result = context[key](args);
    // If you are concerned that the first parameter is context, you can do so
    // let args = [...argument].slice(1);
    
    delete context[key];	
    return result;
}

5. Handwritten bind() function

The bind() method creates a new function whose this is specified as the first parameter of bind() when bind() is called, and the rest of the parameters are used as parameters of the new function for the call.

  • Bid returns a function that is called in two ways:
    • Direct call,
    • Build with new
  • For direct calls, apply() can be used, but note the following:
    • Bid implements code like f.bind(obj, 1)(2), so we need to stitch the internal and external parameters together.
  • For the new method, the direction of this will not be changed, so don't consider passing in this, just stitch in the internal and external parameters directly;
Function.prototype.myBind = function(context,...outerArgs){
    let self = this;	// Storage function caller
    return F(...innerArgs){
        if(self instance of F){	// If new type is used to create
            return new self(...outerArgs,...innerArgs);
        }
        
        // If called directly
        return self.apply(context,[...outerArgs , ...innerArgs]);
    }
}

6. Handwriting instanceof

The instanceof operator detects whether the prototype property of the constructor appears on the prototype chain of an instance object.

Determines whether an instance object is on a prototype chain.

function myInstanceof(exmaple,classFunc){
    let proto = Object.getPrototypeOf(exmaple);
    while(true) {
        if( proto == null ) return false;	// Until you find the prototype null for Object
        
        // Judge Current
        if( proto == classFunc.prototype ) return true;		//
        
        proto = Object.getProtypeOf(proto);		// Get prototype of proto and follow prototype chain all the time;
        // You can also replace it with this: proto = proto. u Proto_u
    }
}

7. Handwriting new

The new operator creates an instance of a user-defined object type or a built-in object with a constructor.

What has new done?

  1. Create a brand new object
  2. _u of this object proto_u prototype to point to constructor
  3. Execute the constructor and use call/apply to change the direction of this
  4. If the return value is of type object, it is returned as the return value of the new method, otherwise it is returned as the new object above
function myNew(fn,...args){
    // Pass in a constructor
    // Parameters passed into the constructor
    
    // Create a new object whose prototype points to the prototype of fn
    let instance = Object.create(fn.prototype)
    let res = fn.apply(instance,args);	// Change the direction of this
    
    // Ensure that the returned value is object
    return typeof res === 'object' ? res : instance;
}

Topics: Javascript node.js Front-end Interview