Handwritten common interview questions

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;
}

Code address: https://github.com/leopord-lau/EasyPresentation

Keywords: Javascript

Added by Scorptique on Mon, 14 Feb 2022 16:41:42 +0200