The difference

When you first come across a need for call, apply, or bind, it’s all but certainly for a one-off use. This article’s about why using these tools for a one-off use isn’t quite intuitive.

What we’re used to

There’s a theme in javascript, one everybody’s used to, conciously or otherwise.

light.on = user.isHome;
light.turnOn(user.isHome);

When it’s time to change your data, you’re either using a method(.turnOn) or operator(=)

// changee   | changer |   change by
   light.on       =       user.isHome    ; // changes `light` with `=`
   light      .turnOn(    user.isHome   ); // changes `light` with a method

What’s on the left is what’s changed — in the lines above and hundreds of others you’ve seen.

Your ‘object to modify’, ‘target’, ‘changee’, whatever-you-call-it, is leftward.

The Surprise

So you want to use a method found elsewhere as if it belongs to your object.

arguments is a good candidate; it looks like an array, but it only has .length

showArgs('foo', 'bar')  // logs: ['foo','bar']
function showArgs(){
  console.log(arguments);
}

You want to use array methods to join arguments into a space-separated string, and arguments is kind of an array, so your gut says do something like this:

focus on `arguments`
    get a function from somewhere else
        use `array.join`
      now execute it
          use ' ' as the separator

so you might do either of the following

arguments.join = Array.prototype.join;
arguments.join(' ');      // which works! but it's two lines.
                          // they'll always need to be modified together and
                          // you'll need both lines each time you want to use one new function

              /* so you shoot for a one-liner */

// change-ee followed by change-er
arguments.borrow(Array.prototype.join)(' ');   // intuitive, but fruitless.
// or
arguments.borrow(Array.prototype.join).callWith(' '); // intuitive, but fruitless.

Alas, you’ll find out the line you want has to start with Array, despite it being all about arguments.

Array.prototype.join.call(arguments, ' ');  // works, but it breaks the mold

All that ‘changee leftwards’ scheme doesn’t fit.

It’s different in two big ways:

Neither makes it easier to remember.

Memory Tricks

this manipulation hasn’t cooperated with the ‘norm’, syntactically or lexically. So, since following precedent didn’t work, here are some memory tricks.

Remembering Syntax

Writing code gives absolute control over what you make, but for this, imagine your objects as moody and/or possesive; pretend they’re people:

here’s the two of us.

me = {
  lawn: 'long-grass',
};

neighbor = {
  lawn: 'short-grass',
  runLawnmower: function(){ this.lawn = 'short-grass'; }
};

with that scenario

// can't call
me.runLawnmower() // !!! error

// and your gut says this syntax would be nice
me.borrowAndExec(neighbor.runLawnmower) // !!! fake syntax

// the line above is stealing; objects want to loan things out

// Instead you have to ask your neighbor to do it
// neighbor.runLawnmower.loanTo(me)
// with the correct identifier
neighbor.runLawnmower.call(me)

hopefully, a little personification can go a long way.

Remembering Vocab

call and apply

Because they’re alive, they’ll respond right away

action

and to differentiate between the two

apply uses an Array, and call uses Commas

Use them for quick or one-off applications.

Array.prototype.join.call(callInContext, 'separator');
Array.prototype.join.apply(callInContext, ['separator']);

bind

with .bind things stick around.

bind function

calling bind lets you save things for later:

boundJoin = Array.prototype.join.bind(callInContext);

// do other stuff

boundJoin(' ');