About some important api implementations in JS, consolidate your native JS skills

Keywords: Javascript

In the interview, often encounter some handwritten XXX and other interview questions, so a good summary is necessary to consolidate the foundation of our native js.

Although there are a lot of summary articles on the Internet, there seems to me a common problem, that is, to complicate the principle too much. If you stand in the interviewer's perspective, his purpose is to inspect the interviewer's understanding of JS language in the shortest time, but after reading many summary articles on the website, I found that a large part of the code is to do meaningless operations, such as achieving a simple shake-proof, as long as it is the core process exhibition. As for other modes, there is no need to dig deeper. A lot of if-else makes people look dazzled and even mislead others to recite the code directly. In addition, the core logic can be displayed, and it is not a problem to realize other similar situations horizontally.

In the following collation, I suggest that you first take the core points and write them by yourself, and then refer to the following code, review the effect is better. The purpose of this article is to help you understand the internal operation process of the API from the perspective of first principles with the most concise code, without dealing with the boundary conditions that are not helpful for us to understand the api.

1. map Method for Array Implementation with ES5

Core points:

  1. What are the parameters of the callback function and how to deal with the return value?
  2. Do not modify the original array.
Array.prototype.MyMap = function(fn, context){
  var arr = Array.prototype.slice.call(this);//Because it's ES5, there's no need for the... Expansion.
  var mappedArr = [];
  for (var i = 0; i < arr.length; i++ ){
    mappedArr.push(fn.call(context, arr[i], i, this));
  }
  return mappedArr;
}

2. Reduction Method of Array Using ES5

Core points:

  1. How to Handle Initial Value Not Passing
  2. What are the parameters of the callback function and how to deal with the return value?
Array.prototype.myReduce = function(fn, initialValue) {
  var arr = Array.prototype.slice.call(this);
  var res, startIndex;
  res = initialValue ? initialValue : arr[0];
  startIndex = initialValue ? 0 : 1;
  for(var i = startIndex; i < arr.length; i++) {
    res = fn.call(null, res, arr[i], i, this);
  }
  return res;
}

Implementing call/apply

Idea: Make use of the context characteristics of this.

//To implement apply, simply replace... Args in the next line with args 
Function.prototype.myCall = function(context = window, ...args) {
  let func = this;
  let fn = Symbol("fn");
  context[fn] = func;

  let res = context[fn](...args);//Key code, using this pointer, is equivalent to context.caller(...args)

  delete context[fn];
  return res;
}

4. Implementing Object.create method (commonly used)

function create(proto) {
    function F() {};
    F.prototype = proto;
    F.prototype.constructor = F;
    
    return new F();
}

5. Implementation of bind method

Core points:

  1. For normal functions, bind this to point.
  2. For constructors, the attributes on the prototype object of the original function should not be lost.
Function.prototype.bind = function(context, ...args) {
    let self = this;//Keep in mind that this represents a function that calls bind
    let fBound = function() {
        //This instance of fBound is true for the constructor. For example, new func.bind(obj)
        return self.apply(this instanceof fBound ? this : context || window, args.concat(Array.prototype.slice.call(arguments)));
    }
    fBound.prototype = Object.create(this.prototype);//Guarantee that the attributes on the prototype object of the original function are not lost
    return fBound;
}

The handwritten bind, as you usually say, is actually as simple as that:)

6. Implementing new keywords

Core points:

  1. Create a completely new object that points _proto_ to the prototype object of the constructor.
  2. Execute the constructor.
  3. The return value of the object type is returned as the return value of the new method, otherwise the new object mentioned above is returned.
function myNew(fn, ...args) {
    let instance = Object.create(fn.prototype);
    let res = fn.apply(instance, args);
    return typeof res === 'object' ? res: instance;
}

Implementing the role of instanceof

Core Points: Looking up the prototype chain.

function myInstanceof(left, right) {
    let proto = Object.getPrototypeOf(left);
    while(true) {
        if(proto == null) return false;
        if(proto == right.prototype) return true;
        proto = Object.getPrototypeof(proto);
    }
}

8. Realizing the Single Case Model

Core Points: Intercepting with Closures and Proxy Attributes

function proxy(func) {
    let instance;
    let handler = {
        constructor(target, args) {
            if(!instance) {
                instance = Reflect.constructor(fun, args);
            }
            return instance;
        }
    }
    return new Proxy(func, handler);
}

9. flat implementation of arrays

In fact, there are many ways. I have done system sorting before. There are six ways. Please refer to:

Summary of flat methods for JS arrays

10. Implementing Anti-shaking Function

Core points:

  1. If triggered again within the timer's time range, the timer is recommenced.
const debounce = (fn, delay) => {
  let timer = null;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

XI. Realizing Throttle Function

Core points:

  1. If triggered again within the timer's time range, it will not be ignored until the current timer is completed before the next timer can be started.
const throttle = (fn, delay = 500) => {
  let flag = true;
  return (...args) => {
    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this, args);
      flag = true;
    }, delay);
  };
};

Posted by leetee on Mon, 09 Sep 2019 21:13:40 -0700