Customize call, bind, apply methods in javascript

call, bind, apply are all methods on the Function prototype to change the direction of this

Custom Functions

call, bind and apply in JS are implemented in c++. Here we use js code to make a pattern, not to take all the boundary conditions into account, but to make a simple implementation. The three functions have some things to pay attention to when they are used, which need to be taken into account when they are defined

  • When an incoming value is a basic data type, the call, apply, and bind methods convert it to a reference data type, such as when the incoming string becomes a String type, which can be done with Object().
  • When no this point is passed that needs to be changed, the this of the function points to window (in non-strict mode)
  • When the passed this points to null, undefined, the function this points to window (in non-strict mode)

Implementation of call

Note when defining the call function

  • The first parameter receives the changed this pointing to, starting with the second parameter, the parameters required for the function to execute

The implementation code is as follows

Function.prototype.iCall = function (thisArg, ...args) {
  // 1. Get the execution function
  var fn = this
  
  // 2. Bind the function to the passed object
  thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
  thisArg.fn = fn
  var result = thisArg.fn(...args)
  
  // 3. Delete the fn function of the passed object
  delete thisArg.fn
  
  // 4. Return results
  return result
}

function foo(...args) {
  console.log('Bound this For:', this)
  console.log('The parameters passed are:', args)
}

var user = {
  name: 'alice'
}

// Change the foo function this to user and pass the parameters 1, 2, 3
foo.iCall(user, 1, 2, 3)

The result of execution is

Implementation of apply

Notes for defining apply functions

  • The first parameter receives the changed this pointing to, and the second parameter receives the array of parameters required for the function to execute

The implementation code is as follows

Function.prototype.iApply = function(thisArg, args){
   // 1. Get the execution function
   var fn = this
   // 2. Bind the function to the passed object
   thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
   thisArg.fn = fn
   var result = thisArg.fn(...args)
 
   // 3. Delete the fn function of the passed object
   delete thisArg.fn
 
   // 4. Return results
   return result
}

function foo(...args){
  console.log('Bound this For:', this)
  console.log('The parameters passed are:', args)
}

var str = "hello js"
var arr = ['a', 'b', 'c']

foo.iApply(str, arr)

The results are as follows

Implementation of bind

Note when defining the bind function

  • The first parameter receives the changed this pointing, and the second parameter receives the parameters needed for the function to execute
  • Instead of calling the function immediately, the bind function returns a new function that can still continue to pass parameters
Function.prototype.iBind = function (thisArg, ...args) {
  // 1. Get the execution function
  var fn = this
  
  // 2. Bind the function to the passed object
  thisArg = thisArg || thisArg.toString() ? Object(thisArg) : window
  thisArg.fn = fn
  
  return function (...params) {
    // 3. Get the result of the function execution
    var result = thisArg.fn(...args, ...params)
    
    // 4. Delete the fn function of the passed object
    delete thisArg.fn
    
    // 5. Return results
    return result
  }
}

function foo(...args) {
  console.log('Bound this For:', this)
  console.log('The parameters passed are:', args)
}
var num = 0

var fn = foo.iBind(num, 20, 40)
fn(30, 50)

The results are as follows

That's how call, bind, apply are implemented. There's not much code, but you need to understand this point. You can also see my other blog about this point.

Keywords: Javascript

Added by robbyc on Mon, 01 Nov 2021 00:08:17 +0200