Recently the interview is more, often asked handwriting realization, not only to write out, but also understand why, clear. Let me tidy it up here.

new

How to implement new?

  1. new Object()Create an empty objectobj.
  2. Get the constructor, which isargumentsThe first term of theta.
  3. Link the prototype of the new object to the incoming object. Internal properties of new objects__proto__Point to the prototype of the constructorprototypeThe new object can access the properties and methods in the constructor prototype.
  4. useapply, will construct the functionthisPointing to the new object gives the new object access to the constructor’s properties and methods.
  5. Executes the function to get the return value. If the return value is an object, that object is returned. Otherwise returnsobj.
function mynew() {
    let obj = new Object(a);let Con = [].shift.call(arguments);
    obj.__proto__ = Con.prototype;
    let res = Con.apply(obj, arguments)
    return typeof res == 'object' ? res : obj;
}
Copy the code

Note:

[].shift.call(arguments) is the first item to delete and get arguments.

When [].shift.call() passes arguments, call changes the shift method’s this pointer to point to arguments, so shift removes and gets arguments’ first item.

The same is true for an array-like object. []. Slice. The call (the arguments) is equivalent to an Array. The prototype. Slice. The call (the arguments).

Slice () is used to create a new array containing one or more elements of the original array, without affecting the original array.

call,apply,bind

The first argument to call,apply, and bind is all function context this.

The common denominator is the ability to change the context in which a function is executed, passing a method from one object to another, and executing it immediately. Changing the execution context means that object A has A method, and object B also needs the same method. In this case, we let B borrow the method of object A, which not only completes the requirements, but also reduces the memory consumption.

So, B wants to do the same thing that A did

function B( ) {
    A.call(this)}Copy the code

The difference between Apply and call is that the call method takes a list of arguments as its second argument, whereas Apply takes an array of arguments. Apply and call are performed immediately, while bind creates a new function that must be called manually.

To realize the call

Note that they are all methods on function prototypes

  1. Take the object context that’s passed in. (The this argument can be passed as null; when null, it refers to the window.)
  2. Sets the function as a property method of the object. So you set the call method to be a property of the context object.
  3. Process the parameters passed in.
  4. Pass in the parameters and execute the method.
  5. Delete the method.
  6. Returns the result.
Function.prototype.myCall = function (context) {
    var context = context || window;
    context.fn = this; 
    let args = [...arguments].slice(1);
    letresult = context.fn(... args);delete context.fn;
    return result;
}
Copy the code

To realize the apply

The second argument to apply is passed in an array, so you need to check if it exists and expand the array if it does.

Function.prototype.defineApply = function (context, arr) {
    var context = context || window;
    context.fn = this;
    let result;
    // Need to check if there is a second argument
    // Expand the second argument if it exists
    if (arguments[1]) { result = context.fn(... arguments[1]);
    } else {
      result = context.fn();
    }
    delete context.fn;
    return result;
}
Copy the code

To realize the bind

Bind can also change the execution context of an object; unlike Call and apply, the return value is a function that needs to be called later before it is executed.

// Bind with call and apply
Function.prototype.mybind = function (context) {
    let self = this; // Save a reference to the function
    return function () { // Return a new function
        // return self.apply(context, arguments);
        return self.call(context, arguments); }};Copy the code
Function.prototype.myBind = function (context) {
    if (typeof this! = ='function') {
      throw new TypeError('Error')}var _this = this
    var args = [...arguments].slice(1)
    // Return a function
    return function F() {
      // Since we return a function, we can new F(), so we need to determine
      if (this instanceof F) {
        return new_this(... args, ... arguments) }return_this.apply(context, args.concat(... arguments)) } }Copy the code

If the throttle

Image stabilization

Although you trigger the event, I will execute it n seconds after the event is triggered, subject to the latest trigger event.

Maintain a timer to record the current state. If a timer exists, it is deleted, because the latest trigger event prevails. Reset the timer and execute it.

I’m using the closure here, and I’m also saving the timer. If the closure is not used, a new timer is set in each return and the previous deletion cannot be found.

Application scenario: Search for Association, resize the window, and keep clicking during login

function debounce(fn,wait) {
    let timer = null;
    return () = > {
        clearTimeout(timer);
        timer = setTimeout(() = > {
            fn.apply(this.arguments); }, wait); }}Copy the code

The throttle

Events are continuously fired, executed only once in a period of time.

Time stamp: set the initial value to 0. If the current time minus the previous timestamp is greater than the set wait time, the function is executed. Update the current timestamp.

Application scenario: The scroll event is triggered when the mouse is repeatedly clicked

function throttle(func,wait) {
    let pre = 0;
    return () = > {
        let cur = Date.now();
        // If the interval exceeds the specified time, the function is executed.
        if (cur - pre > wait) {
            func.apply(this.arguments);
            pre = Date.now(); }}}Copy the code

Deep copy and shallow copy

Shallow copy

Shallow copy refers to the creation of new data that has an exact copy of the original data attribute values. If the property is of a primitive type, the value of the primitive type is copied. If the attribute is a reference type, the memory address is copied. That is, shallow copies copy a layer, and deep reference types share memory addresses.

Shallow copy mode:

  1. Object.assign
  2. Array.prototype.slice()
  3. Array.prototype.concat()
  4. Extended operator
function slowclone(obj) {
    let cloneobj = {};
    for (let k in obj) {
        if (obj.hasOwnProperty(k)) {
            cloneobj[k]=obj[k]
        }
    }
    return cloneobj;
}
Copy the code

Note: For in traverses the properties in the prototype chain, so use hasOwnProperty to exclude the prototype chain.

Deep copy

Deep copy opens a new stack, two object properties complete the same, but corresponding to two different addresses, modify the properties of one object, does not change the properties of the other object.

Recursively deep copy: iterate through sets of objects until they are full of primitive data types, and then copy.

  1. If it is not an object or null, it is returned without copying.
  2. If it is a Date or re, return a new instance of new.

Note: Objects have the problem of circular references. Objects’ properties refer to the object itself. Therefore, you can create an additional storage space to store the current object and the relationship between the stored objects. To copy the current object, go to the storage space and check whether the object has been copied. If yes, return to the object in the storage space. If no, continue copying.

function deepclone(obj, hash = new Map(a)) {
  if(! obj ||typeofobj ! = ="object") return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  let cloneobj = obj.constructor();
  if (hash.get(obj)) return hash.get(obj);
  hash.set(obj, cloneobj);
  for (let k in obj) {
    if(obj.hasOwnProperty(k)) { cloneobj[k] = deepclone(obj[k], hash); }}return cloneobj;
}
Copy the code

instanceof

Determine if B is on the prototype chain of A. Keep looking for A’s __proto__ until it’s B.prototype or null.

function myinstanceof(A, B) {
    let protoA = A.__proto__;
    let prototypeB = B.prototype;
    while (true) {
        if (protoA == null) {
            return false;
        }
        if (protoA == prototypeB) {
            return true; } protoA = protoA.__proto__; }}Copy the code

Object.create()

Used to create a new object that inherits the prototype of another object (O). So f.prototype = o;

function createObj(o) {
  // The argument o is passed to return the instance's __porto__, which is the explicit prototype of the instance constructor
  function F() {} // constructor
  F.prototype = o;
  return new F(); // Return the instance
}
Copy the code

map

What a Map does is it creates a new array, iterates through the original array, takes each element out and does some transformation and appends it into the new array.

Array.prototype.newMap = function (fn) {
  let newArr = [];
  for (let i = 0; i < this.length; i++) {
    newArr.push(fn(this[i], i, this)); // This refers to the array that calls the newMap method
  }
  return newArr;
};

let arr = [1.2.3];
let res = arr.newMap((a) = > a + 1);
console.log(res);
Copy the code

Reduce parameters are as follows

arr.reduce((previousValue, currentValue, currentIndex, array) => {}, initialValue)
    
Copy the code

Reduce implementation map

Array.prototype.newMap = function (fn, Arg) {
  var res = [];
  this.reduce((prev, curr, index, array) = > {
    res.push(fn.call(Arg, curr, index, array));
  }, 0); // Specify initialValue=0, so start with currentIndex=0, the first one
  return res;
};
Copy the code

forEach

The forEach() method performs the given function once on each element of the array.

arr.forEach(function(currentValue, currentIndex, arr) {}, thisArg)
/ / currentValue required. The current element
/ / currentIndex optional. The index of the current element
/ / arr is optional. The array object to which the current element belongs.
ThisArg This parameter is optional. Used as the value of this when the callback function is executed.
Copy the code
Array.prototype._forEach = function(fn, thisArg) {
    if (typeoffn ! = ='function') throw "Parameters must be functions.";
    if(!Array.isArray(this)) throw "You can only use forEach on arrays.";
    let arr = this;
    for(let i=0; i<arr.length; i++) {
        fn.call(thisArg, arr[i], i, arr)
    }
}
Copy the code

Promise

• A Promise is an object that represents and passes the end result of an asynchronous operation.

Solve the callback hell problem caused by nested callback functions.

Promise

function myPromise(executor) {
  let self = this; // keep this. Prevent this from pointing unclearly to later methods
  self.status = 'pending';// The default state of promise is pending
  self.value = undefined;// Save the value passed by the successful callback
  self.reason = undefined;// Save the value passed by the failed callback
  self.successCB = [];// Stores the callback function corresponding to the depressing state
  self.failCB = [];// Stores the callback function corresponding to the Rejected state
  
  function resolve(value) {
    if (self.status === 'pending') { // This can only be fulfilled by a pending state.
      self.status = 'resolved';// The success function changes its status to Resolved
      self.value = value;// Save the successful values
      self.successCB.forEach(fn= >fn()); }}function reject(reason) {
    if (self.status === 'pending') { // Only the pending state => Rejected state
      self.status = 'rejected';// The failed function modifies its function to Rejected
      self.reason = reason;// Save the failed value
      self.failCB.forEach(fn= >fn()); }}// Catch an exception thrown in the excutor executor
  try {
    executor(resolve,reject)
  } catch (err) {
    reject(err)
  }
}
Copy the code

Promise.prototype.then

Then methods are methods on the prototype chain

myPromise.prototype.then = function (onResolved, onRejected) {
  let self = this;
  if (self.status === 'pending') {
    self.successCB.push(() = > {
      onResolved(self.value);// Pass the success value reserved for resolve as an argument
    })
    self.failCB.push(() = > {
      onRejected(self.reason);// Pass the reject value reserved by the reject function as an argument})}if (self.status === 'resolved') {
    onResolved(self.value);// Pass the success value reserved for resolve as an argument
  }
  if (self.status === 'rejected') {
    onRejected(self.reason);// Pass the reject value reserved by the reject function as an argument}}Copy the code

Promise.all

Promise.all takes an array of Promise objects as arguments, and calls the. Then method when all of the Promise objects in the array are resolved or reject, which are executed concurrently.

The promise.all () method wraps multiple Promise instances into a single Promise object (p), which takes an array (P1, P2,p3) as an argument. The array does not have to be full of Promise objects, but it must have an Iterator interface. Resolve converts it to a Promise object before processing.

The state of the Promise object (p) generated with promise.all () is determined by the Promise objects (P1, P2,p3) in the array;

1. If all Promise objects (P1, P2,p3) become fullfilled, the generated Promise object (P) will also become fullfilled. The results from p1, P2,p3 Promise objects will form an array and be returned to the callback function passed to P.

If p1, P2, and P3 have a Promise object in the Rejected state,p will change to the Rejected state, and the return value of the first rejected object will be passed to p’s callback function.

function myall(promises) {
    return new Promise((resolve, reject) = > {// Return a new Promise
        let ret = [];// Define an empty array to hold the results
        let count = 0;
        let done = (i, data) = > {// Handle data functions
            ret[i] = data;
            count++;
            if (count === promises.length) {// When I is equal to the length of the array passed
                resolve(ret); // Execute resolve and place the result in}}for (let i = 0; i < promises.length; i++){
            promises[i].then((data) = > done(i, data), reject); // Pass the result and index to the done function}})}Copy the code

Promise.race

The promise.race () method again wraps multiple Promise instances into a new Promise instance. const p = Promise.race([p1, p2, p3]);

In the above code, the state of P changes as long as one of the first instances of P1, P2, and P3 changes state. The return value of the first changed Promise instance is passed to p’s callback.

In promise.race(), the promise state can only change once, that is, resolve and reject can only be executed once.

function myrace(promises) {
  return new Promise(function (resolve, reject) {
    for (let i = 0; i < promises.length; i++) { promises[i].then(resolve, reject); }}); }Copy the code

Currie,

Step by step, passing some arguments at a time, and returning a more concrete function that accepts the rest of the arguments. There may be multiple layers of such functions that take partial arguments until the result is returned.

function curry(fn, args) {
    var length = fn.length;// Get the number of fn parameters
    var args = args || [];// Get the last argument
    return function(){// Return a function
        // Get the parameters and convert them to an array
        var newArgs = Array.prototype.slice.call(arguments);
        newArgs=args.concat(newArgs);// Merge this parameter with the last parameter
        if (newArgs.length < length) {// If the number of parameters is smaller than the number of parameters, continue collecting
            return curry.call(this,fn,newArgs);
        }else{
            return fn.apply(this,newArgs);// Otherwise return the result of the function execution}}}Copy the code

The Cremation is also important!

Object. The prototype. The toString () method returns a string, said the Object when the Object is represented as text value or when to expect a string reference Object, this method is called automatically.

When an operation or operation requires a String and the object is not a String, a String conversion is triggered, automatically converting non-string attempts to String.

function curyAdd(){
    var args = Array.prototype.slice.call(arguments);

    var adder = function () { args.push(... arguments);return adder;
    }

    adder.toString = function () {
        return args.reduce((pre, cur) = > {
            return pre+cur;
        },0)}return adder;
}

console.log(cury(1.2) (3));
Copy the code

Ajax

Ajax simply puts an intermediate layer (the Ajax engine) between the user and the server, makes an asynchronous request to the server via an XmlHttpRequest object, gets data from the server, and then updates the page by manipulating the DOM with javascript. Asynchronize user actions and server responses. One of the most critical steps is getting the request data from the server.

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
      console.log(xhr.responseText);
    } else {
      console.error(xhr.statusText); }}}// The type of request, the URL of the request, and whether the request is sent asynchronously
xhr.open("get", url, true);
// Pass in the requested data
xhr.send(null);
Copy the code

I am the dividing line ~~~~

Follow up to meet other supplement!