Metoda traci dostęp do właściwego obiektu dokładnie wtedy, gdy przekazujesz ją jako callback? Właśnie w takich sytuacjach przydaje się bind(), czyli narzędzie pozwalające związać funkcję z konkretną wartością this i opcjonalnie przygotować jej część argumentów. Temat określany skrótowo jako js bind obejmuje także różnice między bind(), call() i apply(), użycie w zdarzeniach oraz typowe pułapki.
Najważniejsze informacje o bind() w JavaScript
- bind() zwraca nową funkcję, ale nie uruchamia jej od razu.
- Pierwszy argument ustala wartość this.
- Kolejne argumenty mogą zostać zapisane z wyprzedzeniem jako częściowa aplikacja.
- Metoda jest szczególnie przydatna przy callbackach i obsłudze zdarzeń.
- Do jednorazowego wywołania lepiej pasują call() lub apply().

Jak działa bind() i co naprawdę zmienia
Podstawowa składnia wygląda tak:
const nowaFunkcja = funkcja.bind(thisArg, argument1, argument2);
Wywołanie bind() tworzy nową funkcję. Oryginalna funkcja pozostaje bez zmian, a przekazana wartość thisArg zostaje zapamiętana na później. To ważne, ponieważ wiele osób oczekuje, że metoda wykona kod natychmiast, podobnie jak zwykłe wywołanie funkcji.
const user = {
name: "Ola",
showName() {
return this.name;
}
};
const showUserName = user.showName.bind(user);
console.log(showUserName()); // "Ola"
Bez bind() odłączenie metody od obiektu mogłoby zmienić sposób ustalenia this. Po przypisaniu showName do osobnej zmiennej funkcja nie jest już wywoływana jako metoda obiektu user. Powiązanie przywraca oczekiwany kontekst, nawet gdy funkcję przekazujemy dalej.
Trzeba też pamiętać, że samo bind() nie kopiuje obiektu ani nie tworzy jego niezależnej wersji. Funkcja nadal korzysta z tego samego obiektu, który został przekazany jako this. Jeśli zmienisz właściwość obiektu, związana funkcja zobaczy nową wartość.
Dlaczego this gubi właściwy kontekst
W JavaScript wartość this zależy przede wszystkim od sposobu wywołania funkcji. Ta sama funkcja może zobaczyć różne wartości, gdy raz uruchomisz ją jako metodę, a innym razem przekażesz jako callback.
const counter = {
value: 10,
showValue() {
console.log(this.value);
}
};
counter.showValue(); // 10
const callback = counter.showValue;
callback(); // brak oczekiwanego obiektu
W drugim przypadku funkcja nie jest już wywoływana przez counter. W trybie ścisłym this będzie równe undefined, więc odczyt właściwości zakończy się błędem. W starszym, niestrictowym kodzie może pojawić się obiekt globalny, co jest jeszcze trudniejsze do wykrycia.
Rozwiązanie z bind() wygląda prosto:
const safeCallback = counter.showValue.bind(counter);
safeCallback(); // 10
W praktyce szczególnie często spotykam ten problem przy przekazywaniu metod do setTimeout(), setInterval(), obsługi formularzy oraz własnych funkcji wyższego rzędu. Jeżeli callback ma korzystać z pól obiektu, zwiąż go przed przekazaniem albo użyj funkcji strzałkowej, która przejmie leksykalne this.
bind() a funkcja strzałkowa
Funkcja strzałkowa nie ma własnego this. Pobiera je z otoczenia, w którym została utworzona, dlatego wywołanie na niej bind() nie zmieni kontekstu w taki sposób jak przy zwykłej funkcji.
const object = {
value: 42,
regular: function () {
return this.value;
},
arrow: () => this.value
};
console.log(object.regular()); // 42
console.log(object.arrow()); // wartość z zewnętrznego kontekstu
Moja praktyczna zasada jest prosta. Funkcję strzałkową wybieram wtedy, gdy chcę świadomie zachować this z otoczenia. bind() stosuję wtedy, gdy mam zwykłą funkcję i chcę jawnie przypisać jej konkretny obiekt albo przygotować argumenty.
Przekazywanie argumentów i częściowa aplikacja
Pierwszy argument bind() określa this, ale wszystkie następne zostają zapamiętane i przekazane do funkcji przy późniejszym wywołaniu. Ta technika nosi nazwę częściowej aplikacji. Przydaje się, gdy wiele wywołań korzysta z tej samej wartości początkowej.
function introduce(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: "Marek" };
const sayHello = introduce.bind(person, "Cześć");
console.log(sayHello("!")); // Cześć, Marek!
console.log(sayHello(".")); // Cześć, Marek.
W tym przykładzie zapisaliśmy zarówno this, jak i pierwszy argument. Drugi argument jest dostarczany dopiero przy wywołaniu. Argumenty dodane później są dołączane do tych przekazanych podczas tworzenia funkcji, a nie zastępują ich.
function multiply(a, b, c) {
return a * b * c;
}
const multiplyByTwo = multiply.bind(null, 2);
console.log(multiplyByTwo(3, 4)); // 24
W funkcji multiply() nie korzystamy z this, dlatego jako pierwszy argument można przekazać null. W tym przypadku interesuje nas wyłącznie przygotowanie wartości 2. Przy zwykłych funkcjach użytkowych takie rozwiązanie bywa czytelne, choć nie zawsze jest najlepsze. Jeśli podobną funkcję da się łatwo zapisać jako krótką funkcję strzałkową, często wybieram prostszą wersję zamiast dokładania dodatkowego powiązania.
bind(), call() i apply() nie służą do tego samego
Te trzy metody często pojawiają się obok siebie, ponieważ wszystkie pozwalają kontrolować this. Różnią się jednak momentem wykonania funkcji i sposobem przekazywania argumentów.
| Metoda | Kiedy funkcja się wykonuje | Argumenty | Typowe zastosowanie |
|---|---|---|---|
bind() |
Dopiero przy późniejszym wywołaniu | Podawane pojedynczo | Callback, metoda przekazywana dalej, częściowa aplikacja |
call() |
Natychmiast | Podawane pojedynczo | Jednorazowe wywołanie z konkretnym this
|
apply() |
Natychmiast | Przekazywane jako tablica | Wywołanie z dynamiczną listą argumentów |
function show(prefix, suffix) {
return `${prefix}${this.name}${suffix}`;
}
const user = { name: "Ania" };
show.call(user, "(", ")");
show.apply(user, ["[", "]"]);
const boundShow = show.bind(user, "{");
boundShow("}");
Najważniejsza różnica jest praktyczna. call() i apply() uruchamiają funkcję od razu, natomiast bind() zwraca funkcję do użycia później. Gdy potrzebuję przekazać gotowy handler do innego fragmentu programu, wybieram bind(). Gdy chcę tylko wykonać funkcję w obcym kontekście, zwykle wystarczy call().
Najczęstsze zastosowania w codziennym kodzie
Obsługa zdarzeń
Metoda jest użyteczna, gdy handler ma korzystać z właściwości instancji klasy. Bez powiązania metoda może stracić dostęp do obiektu, na którym została zdefiniowana.
class ButtonController {
constructor(button) {
this.button = button;
this.handleClick = this.handleClick.bind(this);
button.addEventListener("click", this.handleClick);
}
handleClick() {
this.button.classList.toggle("active");
}
destroy() {
this.button.removeEventListener("click", this.handleClick);
}
}
Warto zwrócić uwagę na zapisanie związanej funkcji w this.handleClick. Wywołanie button.addEventListener("click", this.handleClick.bind(this)) zadziała podczas dodawania zdarzenia, ale przy usuwaniu utworzy się inna funkcja i listener pozostanie aktywny.
Przekazywanie metody jako callbacku
const logger = {
prefix: "[LOG]",
print(message) {
console.log(this.prefix, message);
}
};
const messages = ["Start", "Gotowe"];
messages.forEach(logger.print.bind(logger));
To rozwiązanie działa, ponieważ callback otrzymuje właściwy kontekst przy każdym wywołaniu. Jeżeli jednak funkcja jest tworzona w pętli lub renderowana wiele razy, warto pilnować liczby nowych funkcji, bo nadmiarowe wiązania mogą utrudniać porównywanie referencji i sprzątanie zasobów.
Przeczytaj również: Join JS - Sklejanie tablic w tekst. Pełny przewodnik!
Pożyczanie metod innych obiektów
Można związać metodę wbudowaną z innym obiektem, na przykład wykorzystać metodę tablicy do pracy z obiektem przypominającym tablicę.
const slice = Array.prototype.slice.bind(Array.prototype);
function getArguments() {
return slice(arguments);
}
console.log(getArguments("a", "b")); // ["a", "b"]
To technika spotykana głównie w starszym kodzie. W nowoczesnym JavaScript częściej używa się operatora rest, czyli function getArguments(...items). Mimo to przykład dobrze pokazuje, że bind() może służyć nie tylko do pracy z własnymi klasami.
Pułapki, o których łatwo zapomnieć
Najczęstszy błąd polega na oczekiwaniu, że bind() zmieni istniejącą funkcję. Nie zmienia. Zawsze zwraca nową funkcję, dlatego poprawny kod powinien ją przypisać albo od razu przekazać dalej.
const bound = original.bind(object);
bound();
Drugą pułapką jest wielokrotne tworzenie powiązanej funkcji:
element.addEventListener("click", handler.bind(controller));
element.removeEventListener("click", handler.bind(controller));
Te dwa wywołania tworzą dwa różne obiekty funkcyjne. Aby usunąć listener, trzeba zachować referencję:
const boundHandler = handler.bind(controller);
element.addEventListener("click", boundHandler);
element.removeEventListener("click", boundHandler);
Istnieje też ważny wyjątek związany z użyciem bind() przy konstruktorach. Związanej funkcji można użyć z operatorem new, a wtedy ustawienie this przekazane do bind() jest ignorowane, choć wcześniej przygotowane argumenty nadal zostają wykorzystane.
function User(name, role) {
this.name = name;
this.role = role;
}
const Admin = User.bind(null, "Kasia");
const admin = new Admin("administrator");
console.log(admin.name); // Kasia
console.log(admin.role); // administrator
Nie polecam jednak budować całego stylu programowania na ciągłym wiązaniu metod. bind() rozwiązuje konkretny problem z kontekstem, ale w nowym kodzie czasem czytelniejsza będzie funkcja strzałkowa, zamknięcie albo zwykła funkcja przyjmująca dane jawnie jako argumenty.
Jak rozsądnie korzystać z bind() w nowym kodzie
Najpierw sprawdzam, czy funkcja rzeczywiście korzysta z this. Jeśli nie, wiązanie obiektu jest zbędne i może tylko zaciemnić kod. Gdy problem dotyczy przekazywania metody do callbacku, bind() jest dobrym, czytelnym rozwiązaniem, zwłaszcza w klasach i starszych modułach.
Przy częściowej aplikacji warto ocenić, czy przygotowanie argumentów poprawia czytelność. Dla prostego przypadku zapis z bind() jest wygodny, ale przy kilku etapach przetwarzania zwykła funkcja opakowująca może lepiej pokazać intencję i ułatwić debugowanie.
- Użyj bind(), gdy funkcja ma być wywołana później z ustalonym
this. - Użyj call(), gdy chcesz wykonać ją natychmiast z argumentami zapisanymi osobno.
- Użyj apply(), gdy argumenty masz już w tablicy.
- Wybierz funkcję strzałkową, gdy zależy Ci na leksykalnym this.
- Zachowaj referencję do związanej funkcji, jeśli trzeba ją później usunąć.
Najlepszy test dla bind() to świadome wywołanie funkcji
Nie traktuję bind() jako magicznego sposobu na naprawianie każdego problemu z this. To precyzyjne narzędzie, które tworzy nową funkcję z ustalonym kontekstem i opcjonalnie przygotowanymi argumentami.
Jeśli zapamiętasz jedną rzecz, niech będzie nią różnica między wykonaniem funkcji a przygotowaniem funkcji do późniejszego wykonania. Pierwsze zapewniają call() i apply(), drugie zapewnia bind(). Ta granica wystarcza, żeby większość praktycznych przypadków rozpoznać bez zgadywania.