Call, Apply, Bind....oh My

What the....

"The apply() method calls a function with a given this value and arguments provided as an array (or an array-like object)."

The call() method calls a function with a given this value and arguments provided individually.

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

Another way to use these 3 methods is to use a prototype function of another object with your current object.

We use these methods to force the context inside of another function.

Primarily:

call(), bind(), apply()

ALL functions have these methods automatically (defined on their prototype).

Remember:

Object.getOwnPropertyNames(Function.prototype);
// => ['length', 'name', 'arguments', 'caller', 'constructor', 'bind', 'toString', 'call', 
'apply']

So what's the difference?

call() and apply() both invoke the function immediately

bind() calls a function at a later time based on an when an event happens

call()  vs. apply()

The original JavaScript author said..

...10 days bruh.

Seriously though..

The difference is that there's no difference EXCEPT in the way you pass arguments to them, and how you reference those objects inside your function.

call()

apply()

const team1 = {
  teamName: 'Red',
  captain: 'Ash'
};

displayTeam.call(team1, 'Bob', 'Tom', 'Joe');
const team2 = {
  teamName: 'Blue',
  captain: 'John'
};

const team2members = ['Kelli','Art','Matt'];

displayTeam.apply(team2, team2members);

Takes an argument list

Takes an array of arguments

Use the one  whose arguments signature best suits your intended use.

function displayTeam(member1, member2, member3){
  const display = this.teamName + ' captain is ' +
                this.captain + ' with team members: ' +
                member1 + ', ' + member2 + ', ' + member3;
  console.log(display);
}

apply(this, [args])

REMEMBER: apply() takes an Array of arguments

Pro-tip: (a)pply takes an (a)rray

apply can be invoked on any function/method defined on any other object's prototype

// Call a JavaScript function
const numbers = [5, 6, 2, 3, 7];

// Without using apply
const max = Math.max(5,6,2,3,7);


/* using Math.min, this is actually null as Math doesn't use context for operations */
const max = Math.max.apply(null, numbers); // this would have no prototype since null is set and context

function CreateUser() {
    this.name = arguments[0];
    this.age = arguments[1];
}

const user = {};
CreateUser.apply(user, ['Jason', 88]);
console.log(user.name); // 'Jason'
console.log(user.age); // 88

function SendEmail(){
    MailManAPI.send(this.address, this.text);
}

const email = {
    address = 'jason@devleague.com',
    text = 'Aloooooha'
};

SendEmail.apply(email); // sends e-mail with unique values from existing object

call(this, arg1, arg2,...)

REMEMBER: call() takes a list of arguments

call can be invoked on any function/method defined on any other object's prototype

// Call a JavaScript function

// Without using call
const  max = Math.max(5,6,2,3,7);


/* using Math.min, this is actually null as Math doesn't use context for operations */
const max = Math.max.call(null, 5, 6, 2, 3, 7); // this would have no prototype since null is set and context


function CreateUser(name, age) {
    this.name = name;
    this.age = age;
}

const user = {};
CreateUser.call(user, 'Jason', 88);
console.log(user.name); // 'Jason'
console.log(user.age); // 88

function SendEmail(){
    MailManAPI.send(this.address, this.text);
}

var email = {
    address = 'jason@devleague.com',
    text = 'Aloooooha'
};

SendEmail.call(email); // sends e-mail with unique values from existing object

bind()

Remember:

bind() binds a function to an element to be executed on a future event (click, hover,..)

bind() also takes a list of arguments like..?

call() !!

bind(this, arg1, arg2,...)

REMEMBER: bind() takes a list of arguments

bind can be bound to any function including other object's prototype methods.

 

Remember: a method is just a function attached to an object

//Set property x on global scope
this.name = 'Jason'; 

const human = {
  name: 'Jane',
  getName: function() { return this.name; }
};

// here we call the function in the context of an object
human.getName(); // 'Jane'

// Get reference not to object and it's property but direct to the function
const getName = human.getName;
getName(); // 'Jason' "this" refers to the global object since it's not being 
// invoked in the context of the object that defined it

// Create a new function with 'this' bound to module
const boundGetName = getName.bind(human); //Doesn't invoke now, it says WHEN that 
// functions called, invoke it with the provided context

// NOW we invoke it
boundGetName(); // 'Jane' 
// same as module.getName() but could also be invoked with another object to extract the 
// function for use with other objects

const alien = {
    name: 'Mork',
};

// Now invokes the original human function with a new object as it's context
const boundAlienGetName = getName.bind(alien); 
boundAlienGetName(); // 'Mork'
const myObject = {};

// you can add properties(values) and methods(functions) to an object

myObject.name = 'Sam Object';

myObject.whatIsMyName = function() {
    return this.name;
}

console.log(myObject.whatIsMyName()); // 'Sam Object'

const func = myObject.whatIsMyName;

const otherObject = {
  name: 'Jason Jay'
};

const boundFunc = func.bind(otherObject);

console.log(boundFunc()); // 'Jason Jay'

func.bind(undefined); // isn't doing anything

console.log(func()); // undefined.  `this` isn't anything. there is no context.

Must store reference to bound function. Cannot invoke directly. bind() returns a "bound" instance of the function.

Partial Functions

Partial functions are a way to define some arguments but have others be dynamic

function incrementMe(a, b) {
    return a + b;
}

// set incrementer value
const singleIncrementer = incrementMe.bind(null, 1); 
singleIncrementer(4); // 5

// set incrementer value
const quintupleIncrementer = incrementMe.bind(null, 5); 
quintupleIncrementer(4); // 9
// John Resig's "curry" function from 
// http://ejohn.org/blog/partial-functions-in-javascript/
// which is unfortunately named, as this is not currying -
// it's partial function application.
 
Function.prototype.curry = function() {
    //console.log(this, arguments);
    const fn = this, args = Array.prototype.slice.call(arguments);
    return function() {
      //console.log(this, arguments);
      return fn.apply(this, args.concat(
        Array.prototype.slice.call(arguments)));
    };
  };
 
 
// a sample use
 
function add(a, b) {
  return a + b;
}
 
const partial = add.curry(1);
 
partial(2); // => 3

https://lostechies.com/derickbailey/2012/07/20/partially-applied-functions-in-javascript/

Partial Method and Closures

finish.call(slides)

Call, Apply, Bind....oh My

By DevLeague Coding Bootcamp

Call, Apply, Bind....oh My

Summary of the application of call, apply and bind in JavaScript. Their similarities and differences and application.

  • 1,381