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

Как вызвать функцию с заданным This?

1.0 Junior🔥 91 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Как вызвать функцию с заданным This

Управление контекстом this - это одна из сложных, но мощных возможностей JavaScript. Есть несколько способов явно установить контекст при вызове функции.

1. Метод call()

call() вызывает функцию с заданным this и передаёт аргументы по отдельности:

const person = {
  firstName: 'John',
  lastName: 'Doe',
  greeting() {
    console.log(`Hello, ${this.firstName} ${this.lastName}`);
  }
};

// Обычный вызов
person.greeting(); // "Hello, John Doe"

// Используем call() с другим контекстом
const otherPerson = {
  firstName: 'Jane',
  lastName: 'Smith'
};

person.greeting.call(otherPerson); // "Hello, Jane Smith"

С аргументами:

function greet(greeting, punctuation) {
  console.log(`${greeting}, ${this.name}${punctuation}`);
}

const person = { name: 'Alice' };

greet.call(person, 'Hi', '!'); // "Hi, Alice!"

2. Метод apply()

apply() работает как call(), но принимает аргументы массивом:

function sum(a, b, c) {
  return this.multiplier * (a + b + c);
}

const context = { multiplier: 10 };

// call() - аргументы по одному
sum.call(context, 1, 2, 3); // 60

// apply() - аргументы массивом
sum.apply(context, [1, 2, 3]); // 60

// Полезно при развёртывании массива
const numbers = [1, 2, 3];
sum.apply(context, numbers); // 60

Практический пример - нахождение максимума:

const numbers = [5, 6, 2, 3, 7];

// Math.max нужен правильный this, но здесь это не важно
const max = Math.max.apply(null, numbers); // 7

// Или с new синтаксисом spread:
const max2 = Math.max(...numbers); // 7 (лучше)

3. Метод bind()

bind() создаёт новую функцию с привязанным контекстом (не вызывает сразу):

const person = {
  name: 'Bob',
  introduce() {
    console.log(`My name is ${this.name}`);
  }
};

// bind() возвращает новую функцию
const boundIntroduce = person.introduce.bind(person);

boundIntroduce(); // "My name is Bob"

// Полезно для callbacks
setTimeout(boundIntroduce, 1000);

Отличие от call/apply:

function greet() {
  console.log(`Hello, ${this.name}`);
}

const context = { name: 'Charlie' };

// call() вызывает сразу
greet.call(context); // "Hello, Charlie" (выполняется)

// apply() вызывает сразу
greet.apply(context); // "Hello, Charlie" (выполняется)

// bind() возвращает функцию
const boundGreet = greet.bind(context);
boundGreet(); // "Hello, Charlie" (выполняется при вызове)

4. Bind с частичным применением аргументов

function multiply(a, b) {
  return this.factor * a * b;
}

const context = { factor: 2 };

// bind() с аргументами
const double = multiply.bind(context, 2);
const result = double(5); // 2 * 2 * 5 = 20

5. React - практический пример

Проблема: методы теряют контекст

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  
  handleClick() {
    console.log(this.state); // undefined! this потерян
    this.setState({ count: this.state.count + 1 });
  }
  
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

Решение 1: bind() в конструкторе

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    console.log(this.state); // OK!
    this.setState({ count: this.state.count + 1 });
  }
  
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

Решение 2: стрелочная функция как свойство класса

class Button extends React.Component {
  state = { count: 0 };
  
  handleClick = () => {
    console.log(this.state); // OK! Стрелка наследует this
    this.setState({ count: this.state.count + 1 });
  };
  
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

Решение 3: стрелочная функция в JSX

class Button extends React.Component {
  state = { count: 0 };
  
  handleClick() {
    console.log(this.state);
  }
  
  render() {
    return <button onClick={() => this.handleClick()}>Click</button>;
  }
}

6. Стрелочные функции (автоматический this)

Стрелочные функции наследуют this из окружающего контекста:

const person = {
  name: 'Diana',
  greet() {
    console.log(`Hello from ${this.name}`);
    
    // Обычная функция теряет контекст
    setTimeout(function() {
      console.log(this); // Window (или undefined)
    }, 1000);
    
    // Стрелочная функция наследует this
    setTimeout(() => {
      console.log(`${this.name} is waiting`); // "Diana is waiting"
    }, 1000);
  }
};

person.greet();

7. Использование call() для явного вызова метода родителя

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Dog(name, breed) {
  // Вызываем конструктор родителя с правильным this
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype.bark = function() {
  // Вызываем метод родителя
  Animal.prototype.speak.call(this);
  console.log(`${this.name} barks!`);
};

const dog = new Dog('Max', 'Labrador');
dog.bark();
// "Max makes a sound"
// "Max barks!"

8. Сравнение методов

function display(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

const person = { name: 'Eve' };

// call() - вызывает сразу с аргументами по одному
display.call(person, 'Hi');       // "Hi, Eve"

// apply() - вызывает сразу с аргументами массивом
display.apply(person, ['Hello']); // "Hello, Eve"

// bind() - возвращает новую функцию
const boundDisplay = display.bind(person, 'Hey');
boundDisplay();                    // "Hey, Eve"

9. Практический пример - EventListener

class Counter {
  constructor() {
    this.count = 0;
    this.element = document.querySelector('button');
  }
  
  increment() {
    this.count++;
    console.log(this.count);
  }
  
  attachListener() {
    // Без bind() - this будет button element
    this.element.addEventListener('click', this.increment); // ошибка!
    
    // С bind() - this остаётся Counter
    this.element.addEventListener('click', this.increment.bind(this)); // OK!
  }
}

10. Выводы

Когда использовать:

  • call() - когда нужен быстрый вызов с конкретным контекстом
  • apply() - когда аргументы уже в массиве
  • bind() - когда нужна функция для callbacks, обработчиков событий
  • Стрелочные функции - современный способ сохранять контекст

Best practices:

// Используй стрелочные функции в React и современном коде
const handleClick = () => {
  this.setState({ ... });
};

// bind() в классах для методов
this.handleClick = this.handleClick.bind(this);

// call/apply для функционального программирования
array.forEach(fn.bind(context));

Правильное управление this - это ключ к пониманию JavaScript и написанию надёжного кода.