Handwritten common interview questions
Anti shake
Principle of anti shake function: the callback is executed n seconds after the event is triggered. If it is triggered again within this n seconds, it will be timed again.
There are two situations:
- Execute immediately after clicking
- Non immediate execution after clicking
// Non immediate execution const debounce1 = (fn, delay) => { let timer = null; return (...args) => { if(timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay) } } // Execute immediately const debounce2 = (fn, delay) => { let timer = null; let emitNow = true; return (...args) => { if(timer) clearTimeout(timer); if(emitNow) { fn.apply(this, args); emitNow = false; } else { timer = setTimeout(() => { fn.apply(this, args); emitNow = true; }, delay) } } } // Whether to execute the parameter immediately const debounce3 = (fn, delay, isImmediate) => { let timer = null; let emitNow = true; return (...args) => { if(timer) clearTimeout(timer); if(isImmediate) { if(emitNow) { fn.apply(this, args); emitNow = false; } else { timer = setTimeout(() => { fn.apply(this, args); emitNow = true; }, delay) } } else { timer = setTimeout(() => { fn.apply(this, args); }, delay) } } }
throttle
Principle of anti shake function: it is specified that the function can only be triggered once in a unit time. If the function is triggered multiple times in this unit time, only one will take effect.
There are two situations:
- Execute immediately after clicking
- Non immediate execution after clicking
// Non immediate execution const throttle1 = (fn, delay) => { let isEmit = false; return (...args) => { if(isEmit) return; isEmit = true; setTimeout(() => { fn.apply(this, args); isEmit = false; }, delay); } } // Execute immediately const throttle2 = (fn, delay) => { let isEmit = false; return (...args) => { if(isEmit) return; isEmit = true; fn.apply(this,args); setTimeout(() => { isEmit = false; },delay); } } // Whether to execute immediately is controlled by parameters const throttle3 = (fn, delay, isImmediate) => { let isEmit = false; return (...args) => { if(isEmit) return; isEmit = true; if(isImmediate) { fn.apply(this, args); setTimeout(() => { isEmit = false; },delay); } else { setTimeout(() => { fn.apply(this, args); isEmit = false; }, delay); } } }
Deep cloning
We use JSON most often Parse (JSON. Stringify (obj)) is used to realize cloning, but this method actually has some limitations.
For example:
- It is impossible to clone special objects such as functions and RegExp
- It discards the constructor of the original Object and points to Object
- When an object is referenced circularly, an error will be reported
instanceOf
according to Prototype chain Knowledge, we can quickly know according to the object__ proto__ Property to find its constructor.
const instanceOf = function(object, target) { // Take the prototype object of the target const instance = target.prototype; // Take the implicit prototype of the object to be tested object = object.__proto__; while(true) { if(!object) return false; if(object === instance) return true; object = object.__proto__; } }
new operator
Function of new:
- Create a new object
- Execute this to create a new object
- The new object created will be linked to the prototype object of the function (the _proto _attributeof the new object points to the prototype of the function);
- Use the call method of the function to point the binding object this originally pointing to window to obj. (in this way, when we pass the arguments to the function, the properties of the object will be mounted on obj.)
function createObject() { // Create a new object const obj = {}; // Get the constructor and use the call method to enable arguments to take out the first parameter (constructor) using the shift method const Constructor = [].shift.call(arguments); // Will object__ proto__ Property is linked to the prototype property of the constructor obj.__proto__ = Constructor.prototype; // Point this in the constructor to the object and pass the parameter const result = Constructor.apply(obj, arguments); // Ensure that the return value is an object return typeof ret === "object" ? result : obj; }
Implement call method
We all know that call is used to modify the direction of this, but some students may not understand its principle. Let's write a call method to help understand its principle.
Function.prototype.mycall = function(context) { // The default context is window context = context || window; // Add an attribute to save the function that calls call at the moment. context.fn = this; // Convert arguments to an array and remove the first parameter (context) const args = [...arguments].slice(1); // In this way, when calling a function, this inside the function points to the caller (context); const result = context.fn(...args); delete context.fn; return result; }
Implement the apply method
The principle of apply is very similar to that of call. The only difference is the problem of parameter transmission. The second parameter of apply method is an array composed of all parameters, while the first parameter of call method is the passed in parameter except context.
Function.prototype.myapply = function(context, arr) { // The default context is window context = context || window; // Add an attribute to save the function that calls call at the moment. context.fn = this; // Convert arguments to an array and remove the first parameter (context) let result; if(!arr) { result = context.fn(); } else { result = context.fn(arr); } delete context.fn; return result; }
Implement bind method
Compared with call and apply, the return value of bind method is a function that changes this (that is, it is not called immediately). When the returned function is used as a constructor, this fails, but the passed in parameters are still valid.
The bind() method creates a new function. When this new function is called, the first parameter of bind() will be the this of its runtime, and the following sequence of parameters will be passed in as its parameters before the passed arguments.
Function.prototype.mybind = function(context) { if(typeof this !== 'function') { throw new Error('Uncaught TypeError: not a function') } const args = [...arguments].slice(1); // The prototype used to record the currently passed in function; let Transit = function() {}; const _ = this; const FunctionToBind = function() { const bindArgs = [...arguments]; return _.apply(this instanceof Transit ? this : context, args.concat(bindArgs)); } // Record the prototype of the currently passed in function; Transit.prototype = this.prototype; FunctionToBind.prototype = new Transit(); return FunctionToBind; }