In the interview, often encounter some handwritten XXX interview questions, so a good summary, for consolidating the foundation of our native JS is very necessary.

Although there are so many summary articles on the Internet, it seems to me that there is a common problem with over-complicating things that are rational. If he stood in the interviewer’s point of view, in the shortest time is the purpose of the investigation for the degree of understanding the interviewer for JS language, but after watching the summary page of the website I found there is a big part of the code makes little sense to do the operation, such as the implementation of a simple image stabilization, as long as it is the core process, As for some other modes, there is no need to dig deeply, a lot of if-else makes people look dazzling, even misleading people to recite the code directly, in addition, the core logic can be displayed, and then horizontal implementation of other similar situations is not a problem.

In the following arrangement, it is suggested that we first write according to the core points of their own, and then compare the following code, review effect is better. The goal of this article is to get you to understand the inner workings of an API from a first-principles perspective in the simplest code possible, and not to deal with boundary cases that don’t help us understand the API.

ES5 implements the map method of array

Key points:

1. What are the parameters of the callback function and how to handle the return value?

2. Do not modify the original array.

Array.prototype.MyMap = function(fn, context){
  var arr = Array.prototype.slice.call(this);// Since it is ES5, there is no need to... An operator for
  var mappedArr = [];
  for (var i = 0; i < arr.length; i++ ){
    mappedArr.push(fn.call(context, arr[i], i, this));
  }
  return mappedArr;
}
Copy the code

ES5 implements reduce method of array

Key points:

1. What if the initial value is not transmitted

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;
}
Copy the code

3. Implement call/apply

Take advantage of the contextual nature of this.

// Implement apply by placing... in the next line Replace arGS with args
Function.prototype.myCall = function(context = window, ... args) {
  let func = this;
  let fn = Symbol("fn");
  context[fn] = func;

  letres = context[fn](... args);Context. Caller (... args)

  delete context[fn];
  return res;
}
Copy the code

Object.create ();

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

Implement the bind method

Key points:

1. For normal functions, bind the this pointer

2. For constructors, ensure that properties on the prototype object of the original function are not lost

Function.prototype.bind = function(context, ... args) {
    let self = this;// Remember that this means calling bind
    let fBound = function() {
        // This instanceof fBound is true to indicate the constructor case. Such as 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);// Ensure that attributes on the prototype object of the original function are not lost
    return fBound;
}
Copy the code

Bind by hand:

Implement the new keyword

Key points:

  1. Create a brand new object whose __proto__ points to the constructor’s prototype object
  2. Execute constructor
  3. If the value is object, it is returned as the value of the new method; otherwise, the above new object is returned
function myNew(fn, ... args) {
    let instance = Object.create(fn.prototype);
    let res = fn.apply(instance, args);
    return typeof res === 'object' ? res: instance;
}
Copy the code

7. Realize the role of Instanceof

Key point: look 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); }}Copy the code

Implement singleton pattern

Key point: Intercept with closures and Proxy attributes

function proxy(func) {
    let instance;
    let handler = {
        construct(target, args) {
            if(! instance) { instance =Reflect.construct(func, args);
            }
            returninstance; }}return new Proxy(func, handler);
}
Copy the code

Implement array Flat

In fact, there are many ways. I have done systematic sorting before, and there are six methods for your reference:

JS array flat method summary

X. Realize the function of anti-shake

Key points:

If it is triggered again within the time range of the timer, the timer is reset.

const debounce = (fn, delay) = > {
  let timer = null;
  return (. args) = > {
    clearTimeout(timer);
    timer = setTimeout((a)= > {
      fn.apply(this, args);
    }, delay);
  };
};
Copy the code

Eleventh, realize the throttling function

Key points:

If the timer is triggered again within the time range of the timer, the system ignores it and starts the next timer only after the current timer is complete.

const throttle = (fn, delay = 500) = > {
  let flag = true;
  return (. args) = > {
    if(! flag)return;
    flag = false;
    setTimeout((a)= > {
      fn.apply(this, args);
      flag = true;
    }, delay);
  };
};
Copy the code

Implement EventEmit with publish/subscribe mode

Refer to another article of mine:

The handwritten publish subscription part of the publish-subscribe native JS plug-in package.

Implement deep copy

The following is a simple version of the deep copy, without considering the situation of circular reference and Buffer, Promise, Set, Map processing, if one by one implementation, too complex, writing interview in a short time is not realistic, if you are interested in in-depth implementation:

Deep copy ultimate quest.

const clone = parent= > {
  // Determine the type
  const isType =  (target, type) = > `[object ${type}] `= = =Object.prototype.toString.call(target)

  // Process the re
  const getRegExp = re= > {
    let flags = "";
    if (re.global) flags += "g";
    if (re.ignoreCase) flags += "i";
    if (re.multiline) flags += "m";
    return flags;
  };

  const _clone = parent= > {
    if (parent === null) return null;
    if (typeofparent ! = ="object") return parent;

    let child, proto;

    if (isType(parent, "Array")) {
      // Do special processing for arrays
      child = [];
    } else if (isType(parent, "RegExp")) {
      // Do special processing on re objects
      child = new RegExp(parent.source, getRegExp(parent));
      if (parent.lastIndex) child.lastIndex = parent.lastIndex;
    } else if (isType(parent, "Date")) {
      // Do special processing on the Date object
      child = new Date(parent.getTime());
    } else {
      // Process object prototypes
      proto = Object.getPrototypeOf(parent);
      // Use object.create to break the prototype chain
      child = Object.create(proto);
    }
    for (let i in parent) {
      / / recursion
      child[i] = _clone(parent[i]);
    }
    return child;
  };
  return _clone(parent);
};
Copy the code

Fulfill the Promise

Key points and difficult points are more complex, please refer to my other step-by-step dismantling article:

How do I fulfill promises

Using ES5 to achieve the effect of class inheritance

It is also the key knowledge. I have done detailed disassembly before, and there are five versions. If each version can be clearly explained, it can well reflect my understanding of the prototype chain.

ES5 implements inheritance