Register to get access to free programming courses with interactive exercises

Binding (bind) JS: Introduction to Object Oriented Programming (OOP)

JavaScript is an asynchronous programming language. Because of this, functions are often called as other function callbacks. There's a particularly large amount of it in the browser, where there's a callback upon callback upon callback. While we've been working with simple functions, this hasn't been a problem, but things change when we use methods.

We haven't worked with asynchrony yet at this point, but that shouldn't stop us from getting the idea. In a nutshell, the setTimeout function takes a function on input, and the time, after which, it should be called. When the time comes, I'll do it. That's pretty much it.

Try running this code:

const printer = {
  name: 'Hexlet',
  print(greeting = 'hello') {
    console.log(`${greeting}, ${this.name}`);
  }
};

// Direct launch
printer.print(); // => "hello, Hexlet"

Now the same code, but we don't want to it immediately, but rather after a second. To do this, use the setTimeout(), function, which calls the passed function after the specified amount of time.

// We want to run the print method after a second
// Be sure to run this code on your computer
// to get a feel for how setTimeout works
// 1000 means 1000 milliseconds or 1 second
// printer.print is not a call, but a function pass
setTimeout(printer.print, 1000);

// After a second
// => "hello, undefined"

This code will output hello, undefined. Why? Because we didn't pass the printer object inside setTimeout() but rather the print() function without an object. This means that this function has lost its connection to the object itself and its this no longer points to the object. That's how you can illustrate what's going on:

const print = printer.print;
// Somewhere inside setTimeout
print(); // => "hello, undefined"

If there's no context, then this equals an empty object, if we talk about normal functions.

This behavior is often undesirable. Almost always, when a method is passed, it's assumed that it will be called in the context of the object to which it belongs. There are several ways to achieve this behavior. The easiest is to wrap the function in a function while we call the function.

setTimeout(() => printer.print(), 1000);
// After a second
// => "hello, Hexlet"

// Or without setTimeout
const fn = () => printer.print();
// It all works because print() is called from printer
fn(); // => "hello, Hexlet"

This is a common solution that also helps to grab external variables when they're needed for a call:

// Wrapping it in a function helps to pass data inside
const value = 'hi';
setTimeout(() => printer.print(value), 1000);
// => "hi, Hexlet"

Bind

Another way is to use the bind() method. The bind() method is available to functions, and its task is to bind a function to some context. The bind() results in a new function that works like the original one but with context bound to it.

// The context is the same printer object in which the method is defined
// It looks pretty weird, but life is complicated.
// bind is called on a function and returns a function
const boundPrint = printer.print.bind(printer);

// Now you can do it like this
boundPrint(); // => "hello, Hexlet"
setTimeout(boundPrint, 1000);
// In a second
// => "hello, Hexlet"

// It's possible to call bind on the spot
// as the function returns
setTimeout(printer.print.bind(printer), 1000);
// hello, Hexlet

The linked function merges tightly with its context. this won't change anymore.

bind() takes the parameters that the function requires as input in addition to the context. And not all of them at once, but any part of them. bind() will substitute them partially in the new function (the one that's returned from the bind()) method). This technique is called “partial function application”. That way, you can apply the right arguments right away:

setTimeout(printer.print.bind(printer, 'hi'), 1000);
// After a second
// => "hi, Hexlet"

The bind() approach was popular before the advent of arrow functions, now it isn't used so often. Arrow functions are easier to understand and are used everywhere.

Apply & Call

bind() is useful where context binding and function calls occur in different places and usually at different times. We will encounter such code when we move on to asynchrony in JavaScript.

Sometimes, functions that use this internally are called straight away, with context binding alongside it. This can be done directly by immediately calling the function returned by bind: ...bind(/* context */)():

const print = printer.print;
print.bind(printer)('hi'); // => "hi, Hexlet"

or you can use the apply() and call() functions specially created for this purpose:

// func.apply(thisArg, [ argsArray])
print.apply(printer, ['hi']); // hi, Hexlet

// func.call([thisArg[, arg1, arg2, ...argN]])
print.call(printer, 'hi'); // hi, Hexlet

These functions do two things internally: they change the context and immediately make a function call. The only difference is how they handle the arguments of these functions: apply() takes arguments with an array as the second parameter, while call() takes positional arguments as input.

These features allow you to do some pretty unusual things, like this:

// If there's no context, it passes null
const numbers = [1, 10, 33, 9, 15]
const max = Math.max.apply(null, numbers); // 33

const numbers = [1, 10, 33, 9, 15]
const max = Math.max.call(null, ...numbers); // 33

The call above is just a demonstration, it's of little practical use. The real use of call() and apply() shows up in the binding of contexts to functions from the prototypes. We'll talk about this in future lessons.


Recommended materials

  1. apply()

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs

From a novice to a developer. Get a job or your money back!

Frontend Developer icon
Profession
beginner
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.