This is the 22nd day of my participation in Gwen Challenge

preface

If we meet the need to handwritten code, shake throttling is a relatively high frequency (the link can be clicked here, previously implemented), handwritten implementation of apply,call,bind is also asked more, today we have a good study, to see how to handwritten implementation.

usage

Before implementing apply,call, and bind by hand, we need to see how they are used. First understand the usage, then see how to implement.

apply

Change the orientation of this in the function at runtime. Grammar:

func.apply(thisArg, [argsArray])

ThisArg: object to which this points when the function is run, mandatory argsArray: argument passed when the function is run, array form, optional

Example:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: 'the answer cp3'}
fn.apply(obj, [1.2.3])
// Output the answer cp3 1 2 3
Copy the code

As you can see, fn points to obj and disassembles the array as an argument passed in by the function.

call

Just like apply, this changes the orientation of this inside the function when the function is run.

The difference is that the parameters passed by apply must be arrays. Call does not have this restriction.

Grammar:

func.call(thisArg[, args1, args2, args3,….] )

ThisArg: object to which this points when the function is run, mandatory args1, etc. : parameter passed when the function is run, optional

Example:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: 'the answer cp3'}
fn.call(obj, 1.2.3)
// Output the answer cp3 1 2 3
Copy the code

As you can see, fn executes pointing to obj and collects all the arguments as passed in by the function.

bind

Unlike apply and call, bind does not execute functions. It returns a new function and then binds this to that new function.

Grammar:

func.bind(thisArg[, args1, args2, args3,….] )

Example:

function fn (a, b, c, d) {
    console.log(this.name)
    console.log(a, b, c, d)
}
let obj = {name: 'the answer cp3'}
let bindFn = fn.bind(obj, 1.2.3)
bindFn('bind') Cp3 1 2 3 'bind'
Copy the code

Bind returns a new function. This points to obj when the new function is executed, and the arguments passed in bind are merged with those passed in when the new function is called.

Handwritten implementation

Apply,call,bind

  1. apply.call.bindEverything can changethisThe point to
  2. apply.callWill execute the called function,bindReturns a new function.
  3. applyThe second requirement is an array,call.bindThere is no restriction on the data type, it will pass the rest of the arguments to the function,bindIt also merges the parameters passed in the new function call and passes them to the new function.
  4. They are all bound toFunctiontheprototypeOn.

Now let’s see how to do it by hand. Because they’re all tied to Function prototype, so are we, but we’ll call them _apply, _call, _bind

apply

Function.prototype._apply = function (context, args) {
  // Default is global, window
  context = context || window
  // Args defaults to an empty array, preventing the spread operator from reporting an error below
  args = args ? args : []
  // Store this in context.fn, where this is the function being called
  context.fn = this
  // Execute the called function, this points to context, and the argument is extended with the spread operator
  constres = context.fn(... args)// Delete without polluting the context
  delete context.fn
  / / returns the res
  return res
}
Copy the code

Verify with the above example:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: 'the answer cp3'}
fn._apply(obj, [1.2.3])
// Output the answer cp3 1 2 3
Copy the code

Through ~

call

Call is the same as apply, except that the parameters of call are different from those of apply.

The code is as follows:

Function.prototype._call = function (context, ... args) {
  // Default is global, window
  context = context || window
  // Args defaults to an empty array, preventing the spread operator from reporting an error below
  args = args ? args : []
  // Store this in context.fn, where this is the function being called
  context.fn = this
  // Execute the called function, this points to context, and the argument is extended with the spread operator
  constres = context.fn(... args)// Delete without polluting the context
  delete context.fn
  / / returns the res
  return res
}
Copy the code

The spread operator is used to fetch args for the second argument of the _call function, so that the rest of the arguments are fetched into args, and everything else is the same.

Verify with the above example:

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: 'the answer cp3'}
fn._call(obj, 1.2.3)
// Output the answer cp3 1 2 3
Copy the code

Also through ~

bind

Bind is different in that it returns a new function that can be called or treated as a constructor using the new operator, so there’s a distinction to be made here.

Function.prototype._bind = function (context, ... args) {
  // Default is global, window
  context = context || window
  // Save this to fn, where this is the function called
  let fn = this
  return function newFn (. fnArgs) {
    let res
    // Consider whether the new function will be treated as a constructor
    if (this instanceof newFn) {
      // If it is a constructor, call new and merge the args, fnArgs parameters
      res = newfn(... args, ... fnArgs) }else {
      The _call defined above can also be used as a normal function callres = fn.call(context, ... args, ... fnArgs) }return res
  }
}
Copy the code

Verify with the above example:

function fn (a, b, c, d) {
    console.log(this.name)
    console.log(a, b, c, d)
}
let obj = {name: 'the answer cp3'}
let bindFn = fn._bind(obj, 1.2.3)
bindFn('bind') Cp3 1 2 3 'bind'
Copy the code
let bindFn = fn._bind(obj, 1.2.3)
let instance = new bindFn()
instance.constructor === fn // true
Copy the code

Also through ~

conclusion

The above is a summary of the handwritten implementation of apply,call,bind, if you do not understand or write questions, welcome comment communication ~