preface

We must get rid of the comfort zone, only with time can you get what you want, or the same words, what is the use of light envy, we have to act.

Call and apply

If we want to change the this reference inside a function, there are three methods, of which call and apply are similar

const res = myFn.call(context, ... args); const res = myFn.apply(context, args);Copy the code

In both cases, the function context and other parameters are passed in and the return value is obtained. The other parameters are passed in different ways.

Therefore, implementing these two methods is relatively simple:

  • Declare a myCall/myApply function
  • Internally throughargumentsGets the context passed incontext, and other remaining parametersargs
  • The function for that method is calledfn(fn = this) mounts tocontexton
  • throughcontext.fnMethod to call
  • Deletes the mounted temporary property and returns the result
myCall(context, ... Args) {// Check whether the caller is a function. If (typeof this! == "function") { throw new Error("need function"); } const fnKey = Symbol(); Context is null, undefined, etc. If (! context) { context = window; } // Mount, call context[fnKey] = this; const res = context[fnKey](... args); delete context[fnKey]; return res; }Copy the code

bind

Bind is special here because it not only changes the context this, but also returns a completely new function (instead of calling it directly). Here are a few things to note:

  • Additional arguments passed when bindIt’s going to come laterThe actual arguments passed when calledbefore
  • The returned function may benewOperator call

new

No. The new one

What happened to the new process?

  • Create a new object, obj

  • __proto__ = cons. prototype or object.setProtoTypeof (obj, cons.prototype).

  • Call cons. call(obj,… args)

  • Judge by the return value of the constructornewWhat to return

    • If the constructor returnsThe base typeIf there is no return statement, undefined is returnednewThe action returns the newly created obj object
    • If the constructor returns a reference type, the new operator is ignored and the constructor’s return value is returned

Write a new

function New(fn, ... args) { const obj = {}; Object.setPrototypeOf(obj, fn); Prototype // const obj = object. create(fn. Prototype) const res = fn. Call (obj,... args); Return res instanceof Object? res : obj; }Copy the code

To realize the bind

myBind(context, ... preArgs) { const fn = this; if (typeof fn ! == "function") { throw new Error("need function"); } function newFn(... Args) {// If the external is called by the new operator // if it is, the previously passed context will be nullified.the procedure this refers to the newly created obj will call(obj) the constructor. So the current context this is obj const isByNew = this instanceof fn? this : context; / /!!!!! Focus!!!!! const newContext = isByNew ? this : context; return fn.call(newContext, ... preArgs, ... args); } // make sure that the arrow function does not have a prototype NewFn. Prototype = object.create (fn. Prototype); } return newFn; Function (prototype) {// const F = function () {}; // F.prototype = prototype; // return new F(); / /}Copy the code

The logic here is a little convoluted, but it’s easy to understand the isByNew process if you know that cons. call(obj) happens to new.

Extend the instanceof operator

Don’t sleep, we can expand, and finally instanceof

The instanceof operator is used to determine if there is a reference to the constructor’s prototype object on the prototype chain (__proto__ property) of the object

SetPrototype (obj, cons. prototype) obj instanceof Cons === true

The soul of torture

What if I do a bind to the arrow function?

We might as well try

const arrow = () => { console.log(this.a) }; arrow(); // undefined a = 1; arrow(); // 1 const bindArrow = arrow.bind({a: 2}); bindArrow(); / / 1Copy the code

As you can see, when we bind the arrow function, the context that was passed in is ignored.