← Назад к вопросам

Как работает bind для функций?

1.3 Junior🔥 231 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает bind для функций в JavaScript

bind() — метод, который создаёт новую функцию с привязанным контекстом (this) и опционально зафиксированными аргументами. Это отличается от call() и apply(), которые вызывают функцию сразу.

Основной синтаксис

// bind() создаёт НОВУЮ функцию, но не вызывает её
const boundFunction = originalFunction.bind(thisArg, arg1, arg2, ...);

// Затем ты можешь вызвать её когда угодно
boundFunction(arg3, arg4);

Проблема: контекст this

Без bind() контекст this может быть потерян:

const person = {
  name: 'Иван',
  greet() {
    console.log(`Привет, ${this.name}`);
  }
};

// ❌ Потеря контекста
const greet = person.greet;
greet();                    // Error: this.name undefined (this = window/global)

// ✅ С bind()
const boundGreet = person.greet.bind(person);
boundGreet();               // "Привет, Иван"

Привязка контекста (this)

const user = {
  id: 1,
  name: 'Alice',
  getId() {
    return this.id;
  }
};

// bind() создаёт функцию с фиксированным this
const getUserId = user.getId.bind(user);
console.log(getUserId());   // 1

// Можешь привязать к другому объекту
const admin = { id: 999 };
const getAdminId = user.getId.bind(admin);
console.log(getAdminId());  // 999

Partial Application (Частичное применение аргументов)

function multiply(a, b, c) {
  return a * b * c;
}

// Зафиксируй первые аргументы
const multiplyBy2And3 = multiply.bind(null, 2, 3);
console.log(multiplyBy2And3(4));     // 2 * 3 * 4 = 24

// Полезно для callback'ов
const double = multiply.bind(null, 2, 1);
console.log(double(5));              // 2 * 1 * 5 = 10

Практические примеры в Node.js Backend

1. Сохранение контекста в callback'ах

class UserService {
  private db: Database;
  
  constructor(db: Database) {
    this.db = db;
  }
  
  async fetchUser(id: string) {
    return this.db.query('SELECT * FROM users WHERE id = ?', [id]);
  }
  
  async process(ids: string[]) {
    // ❌ Потеря this
    // ids.forEach(function(id) {
    //   this.fetchUser(id); // this === undefined
    // });
    
    // ✅ С bind()
    ids.forEach(this.fetchUser.bind(this));
    
    // ✅ Или используй стрелочные функции
    ids.forEach(id => this.fetchUser(id));
  }
}

2. Event listeners

class EventManager {
  name: string = 'Manager';
  
  onEvent(event: Event) {
    console.log(`${this.name} received:`, event);
  }
  
  setup(target: EventTarget) {
    // ❌ Потеря this
    // target.addEventListener('click', this.onEvent);
    
    // ✅ С bind()
    target.addEventListener('click', this.onEvent.bind(this));
  }
}

const manager = new EventManager();
manager.setup(button);

3. SetTimeout и setInterval

class Timer {
  interval: number = 1000;
  
  logTime() {
    console.log(new Date().toISOString());
  }
  
  start() {
    // ❌ Потеря this
    // setInterval(this.logTime, this.interval);
    
    // ✅ С bind()
    setInterval(this.logTime.bind(this), this.interval);
  }
}

const timer = new Timer();
timer.start();

4. Создание функций-обработчиков с аргументами

class DataProcessor {
  async processItem(id: string, options: any) {
    const data = await this.fetch(id);
    return { ...data, ...options };
  }
  
  async processMany(ids: string[], options: any) {
    // Создаём функцию с зафиксированным options
    const processor = this.processItem.bind(this, undefined, options);
    
    // Проблема: bind фиксирует аргументы слева
    // Лучше использовать стрелочную функцию:
    return Promise.all(
      ids.map(id => this.processItem(id, options))
    );
  }
}

Сравнение: bind, call, apply

function introduce(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Bob' };

// call() — вызывает сразу
introduce.call(person, 'Hello', '!');          // "Hello, Bob!"

// apply() — вызывает сразу, аргументы массивом
introduce.apply(person, ['Hi', '?']);          // "Hi, Bob?"

// bind() — возвращает новую функцию
const greet = introduce.bind(person, 'Hey');
greet('...');                                   // "Hey, Bob..."

TypeScript: стрелочные функции vs bind()

// Стрелочные функции (предпочтительно)
class Service {
  name = 'Service';
  
  // this автоматически привязан в стрелочной функции
  handleClick = () => {
    console.log(this.name);
  };
}

// vs bind() в конструкторе
class OldService {
  name = 'OldService';
  
  constructor() {
    // Нужно явно привязывать
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    console.log(this.name);
  };
}

Ключевые моменты

  • bind() не вызывает функцию, возвращает новую
  • Контекст this зафиксирован и не может быть изменён
  • Частичное применение аргументов работает (currying)
  • В TypeScript и современном JS предпочитай стрелочные функции
  • bind() всё ещё нужен для интеграции с legacy кодом