1. Implement a new operator

What does the new operator do first before implementing itCopy the code
  • Build a brand new object: var obj = {}

  • New creates an instance of the constructor that accesses the properties of the constructor Prototype chain: obj.propt = fn.prototype

  • Const ret = fn.apply(obj) const ret = fn.apply(obj) const ret = fn.apply(obj)

  • Determine the return type of fn, ret if it is an object, and obj if it is a value type

function _new (fn , ... args) { var obj = {} obj.__proto = fn.prototype const ret = fn.apply(obj, args) return typeof ret === 'object' ? ret : obj }Copy the code

2. Implement depth copy

Before we do that, we need to know what is a light and dark copyCopy the code
  • Shallow copy: Only Pointers to an object are copied, not the object itself. The old and new objects share a piece of memory
  • Deep copy: Copy and create an identical object, without sharing memory, modify the new object, leaving the old object unchanged
function shallowCopy(obj) { if (typeof obj ! == 'object') return let newobj = obj instanceof Array ? [] : {} for (let key in obj) { if (obj.hasOwnProperty(key)) { newobj[key] = obj[key] } } return newobj }Copy the code
function deepCopy(obj) { if (typeof obj ! == 'object') return var newobj = obj instanceof Array ? [] : {} for (var key in obj) { newobj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key] } return newobj }Copy the code

3. Implementation of Instanceof

In depth copy we use the instanceof method. Now let's implement this method, which we already know is used to determine the value type. But in fact, its real purpose is to determine whether an object is an instance of another objectCopy the code
    function _instanceof(left, right) {
      let L = left.__proto__
      let R = right.prototype
      while(true) {
        if (L === null) return false
        if (L === R) return true
        L = L.__proto__
      }
    }
Copy the code

4. Hand write call, apply, bind

The difference and usage of the threeCopy the code
  • Call takes multiple arguments, the first of which is the function context (this), followed by arguments to the function itself
  • Apply takes two arguments, the first of which is the function context this and the second of which is the function argument, which is simply passed in as an array
  • Bind takes multiple arguments, the first of which is the return value of bind, which is this of a function context, and is not executed immediately.
Function.prototype.mycall = function (context, ... args) { context = context || window const key = Symbol() context.key = this return context.key(... args) delete context.key() }Copy the code
Function.prototype.myapply = function (context, args) { context = context || window const key = Symbol() context.key = this return context.key(... args) delete context.key() }Copy the code
Function.prototype.mybind = function (context) { context = (typeof context === 'object' ? context : window) return (... args) => { console.log(args) this.call(context, ... args) } }Copy the code

5. Anti-shake and throttling

  • Stabilization: Execute the callback n seconds after the event is triggered. If it is triggered again within n seconds, the timer is reset.
  • Throttling: specifies that functions can be fired only once per unit of time. If more than one function is fired in this unit of time, only one function will take effect.
// function debounce (func, delay) { var timeout return function () { clearTimeout(timeout) timeout = setTimeout(() => { func.apply(this, arguments) }, delay) } }Copy the code
// function throttle(func, delay) { var last = 0 return function() { var now = Date.now() if (now > last + delay) { func.apply(this, Arguments) last = now} else {console.log(' interval time not required ')}}}Copy the code

6. Mr Currie

  • Currying, also known as Partial Evaluation, is a technique of converting a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returning a new function that takes the remaining arguments and returns a result. The core idea is to split the multi-parameter function into a single-parameter (or partial) function, and then return to call the next single-parameter (or partial) function, and process the remaining parameters in turn
    var curry = function (fn) {
      var args = [].slice.call(arguments, 1)
      return function () {
        var newArgs = args.concat([].slice.call(arguments))
        return fn.apply(this, newArgs)
      }
    }
Copy the code

7. Inheritance

/ / prototype chain + constructor function Parent (value) {this. Val = value} the Parent. The prototype. The getValue = function () {the console. The log (enclosing val)}  function Child(value) { Parent.call(this, value) } Child.prototype = new Parent()Copy the code
/ / parasitic inheritance function Parent (value) {this. Val = value} the Parent. The prototype. The getValue = function () {the console. The log (enclosing val)} function Child(value) { Parent.call(this, value) } Child.prototype = Object.create(Parent.prototype, { constructor: { value: Child, enumerable: false, writable: true, configurable: true } })Copy the code
Constructor (value) {this.val = value} getValue() {console.log(this.val)}} class Child extends Parent { constructor(value) { super(value) this.val = value } }Copy the code