This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Call, apply, bind, call, bind, call, bind, call, bind, call, bind

If you feel helpful, please click 👍 to encourage you

call/apply

role

To change the orientation of this inside the function.

The characteristics of

Any function can call these two methods, indicating that they are methods added to the function prototype (Function.prototype).

console.dir(Function.prototype)
Copy the code

callcallapplyThe function is executed immediately.

callapplyIs the return value of the function.

var name = A Warbler's Tail
var obj = {
  name: 'warbler',}function foo() {
  console.log(this.name);
  return 'success'
}
foo.call(obj) //=> warbler
console.log(foo.call(obj)); // => success
Copy the code

callcallapplyPoint to theundefinedornullWill,thisPoint to thewindow.

function foo() {
  console.log(this)
}
foo.call(undefined)
foo.call(null)
foo.apply(undefined)
foo.apply(null)
Copy the code

callcallapplyPoints to a value type, which willthisPoints to instances created by their constructors.

function foo() {
  console.log(this)
}
foo.call(11)
foo.call('11')
foo.call(true)
Copy the code

callcallapplyPoints to a reference type, which willthisPoint to this object.

We declare a global variable name and a function foo in the global scope.

var name = A Warbler's Tail
var obj = {
  name: 'warbler',}function foo() {
  console.log(this.name)
}
foo() //=> a bird
Copy the code

Name is equivalent to window.name, foo() is equivalent to window.foo(), we print this.name, and the current this points to its caller, window, which is window.name, and gets a streamer.

But what if I want to print out Warbler? Define another obj.fn inside obj? Of course not. All we need to do is call Call /apply to redirect this to obj. In this case this.name is equivalent to obj.name, and we get warbler.

foo.call(obj) //=> warbler
foo.apply(obj) //=> warbler
Copy the code

The difference between call and apply

There is no difference except the form of the input.

Parameters passed to fn are written differently:

  • callTakes multiple arguments, the first of which is the function context, i.ethisThe following parameters are parameters of the function itself.
  • applyReceives two arguments, the first of which is the function contextthisThe second argument is a function argument that is simply passed by oneAn array ofIn the form of.

Just remember that apply starts with a and that the argument it passes to fun is Array, which also starts with an A, and you can make a nice distinction between the two functions.

Write a call/apply

Write a call

var name = A Warbler's Tail
var obj = {
  name: 'warbler',}function foo() {
  console.dir(this);
  return 'success'
}

/** * the Object() method returns the instance created by the constructor of the corresponding type if the value type is passed in. * returns the Object itself if the value type is passed in. * Returns an empty Object if undefined or null
Function.prototype._call = function(ctx, ... args) {
  // Determine the context type if undefined or null points to window
  // Otherwise use Object() to wrap the context as an Object
  const o = ctx == undefined ? window : Object(ctx)
  // How to refer this of function foo to CTX context
  // Assign the function foo to a property of object O and call foo on that object o. This refers to that object O
  // This is the function foo that calls _call. When we assign this to fn of object O, we assign foo to o.fin
  // Add a unique attribute to the context to avoid overwriting the original attribute
  const key = Symbol()
  o[key] = this
  // Execute immediately
  constresult = o[key](... args)// Delete this attribute
  delete o[key]
  // Assign the return value of the function to the return value of _call
  return result
}

Copy the code

To verify

foo._call(undefined) // window
foo._call(null) // window
foo._call(1) // Number
foo._call('11') // String
foo._call(true) // Boolean
foo._call(obj) // {name: 'warbler'}
console.log(foo._call(obj)); // success
Copy the code

You can see that our hand-written _call method yields the same result as the native call method.

Handwritten apply

As mentioned earlier, the only difference between call and apply is the way parameters are passed, so we just need to change the way parameters are handled and everything else is the same as call.

var age = 10
var obj = {
  age: 20,}function foo(a, b) {
  console.dir(this.age + a + b);
}
// Just change the second argument to an array.
Function.prototype._apply = function(ctx, array = []) {
  const o = ctx == undefined ? window : Object(ctx)
  // Add a unique attribute to the context to avoid overwriting the original attribute
  const key = Symbol()
  o[key] = this
  constresult = o[key](... array)delete o[key]
  return result
}
foo(3.4) / / = > 17
foo._apply(obj, [3.4]) / / = > 27
Copy the code

bind

role

It’s also used to change the orientation of this inside a function.

Bind and call/apply

Whether to execute immediately:

  • call/applyChange the delta functionthisAfter the contextimmediatelyExecute the function.
  • bindIs the function that returns the changed context,This function is not executed

The difference between return values:

  • call/applyreturnfunThe execution result of.
  • bindreturnfunAnd specifiedfunthisPoint to, savefunThe parameters.
var name = A Warbler's Tail
var obj = {
  name: 'warbler',}// this points to the caller document
document.onclick = function() {
  console.dir(this); // => #document
}

// this points to obj
document.onclick = function() {
  console.dir(this); // => #Object{name:'warbler}
}.bind(obj)

Copy the code

Write a bind

Function.prototype._bind = function(ctx, ... args) {
  // The following this is the function that calls _bind, saved to _self
  const _self = this
  // bind will return a function, it will not be executed immediately
  const newFn = function(. rest) {
    // Call call to modify this reference
    return_self.call(ctx, ... args, ... rest) }if (_self.prototype) {
    // Copy the prototype of the source function to newFn in cases where the function has no prototype, such as the arrow function
    newFn.prototype = Object.create(_self.prototype);
  }
  return newFn
}
Copy the code