Роль this в JavaScript

В JavaScript ключевое слово this имеет решающее значение для обеспечения работы функций в определенном контексте. Чтобы эффективно определить контекст и использовать функции для различных объектов, полезными решениями являются такие методы, как call()apply() и bind(). Рассмотрим эти методы и способы их использования.

Значения this

В JavaScript ключевое слово this представляет собой контекст выполнения функции. Однако его значение меняется в зависимости от того, как и где вызывается функция. Вот несколько базовых понятий.

  • Глобальный контекст: когда функция вызывается в глобальном контексте (например, в окне браузера), this представляет глобальный объект (window).
console.log(this === window); // true
  • Контекст функции: когда функция вызывается как метод объекта, this представляет этот объект.
const obj = {
name: "Object",
logName() {
console.log(this.name);
}
};

obj.logName(); // Вывод: объект
  • Обработчики событий: внутри обработчика события this представляет элемент, вызвавший событие.
document.querySelector("#button").addEventListener("click", function() {
console.log(this); // "this" представляет элемент #button
});
  • Функции-конструкторы: внутри функции-конструктора this представляет собой только что созданный объект.
function Person(name) {
this.name = name;
}

const person1 = new Person("Ozan");
console.log(person1.name); // Вывод: Ozan

Эти базовые понятия обобщены, чтобы заложить основу для понимания того, как можно управлять this с помощью таких методов, как call()apply() и bind().

Метод call()

Базовое использование

function.call(object, arg1, arg2, ...);
  • function: функция, которая будет вызвана с определенным контекстом;
  • object: значение this внутри функции;
  • arg1, arg2, …: аргументы, передаваемые функции.

Пример 1

const obj1 = {
number1: 20,
number2: 50
};

function totalNumber(num1, num2) {
console.log(this.number1 + this.number2 + num1 + num2);
}

totalNumber.call(obj1, 40, 60); // Вывод: 170

Пример 2

const user = {
name: "Reader",
greet(greeting) {
console.log(`${greeting}, ${this.name}!`);
}
};

user.greet.call(user, "Hello"); // Вывод: Hello, Reader!

const admin = {
name: "Admin"
};

user.greet.call(admin, "Hello"); // Вывод: Hello, Admin!

Пример 3

function sum(a, b) {
return this.base + a + b;
}

const context = { base: 10 };

const result = sum.call(context, 5, 7); // Вывод: 22

Пример 4

function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
this.result = total;
}

sum.call(null, 3, 7, 5, 2, 8);
console.log(result); // Вывод: 25

Метод apply(): передача аргументов в виде массива

Метод apply(), как и call(), используется для вызова функции с определенным контекстом. Отличие заключается в том, что аргументы передаются в виде массива.

Базовое использование

function.apply(object, [arg1, arg2, ...]);

Пример 1

const obj1 = {
number1: 20,
number2: 50
};

function totalNumber(num1, num2) {
console.log(this.number1 + this.number2 + num1 + num2);
}

totalNumber.apply(obj1, [40, 60]); // Вывод: 170

Пример 2

const calculator = {
addNumbers: function (num1, num2) {
console.log(`Total: ${this.result + num1 + num2}`);
},
result: 10
};

const numbersToAdd = [5, 7];

calculator.addNumbers.apply(calculator, numbersToAdd); // Вывод: всего: 22

Пример 3

const obj1 = { number: 10 };

function doubleNumber(x) {
console.log(this.number * x);
}

doubleNumber.apply(obj1, [5]); // Вывод: 50

Пример 4

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

function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
this.result = total;
}

sum.apply(null, numbers);
console.log(result); // Вывод: 25

Метод bind(): сохранение контекста для будущего использования

Метод bind() создает новую функцию, при вызове которой ключевое слово this устанавливается в указанное значение.

Базовое использование

const boundFunction = function.bind(object);
boundFunction(arg1, arg2, ...);

Пример 1

const obj2 = {
number1: 60,
number2: 120
};

function totalNumber(num1, num2) {
console.log(this.number1 + this.number2 + num1 + num2);
}

const bindFunction = totalNumber.bind(obj2);
bindFunction(50, 110); // Вывод: 340

Пример 2

const obj1 = {
message: "Hello World!",
greet: function () {
console.log(this.message);
}
};

const obj2 = {
message: "Hello Universe!"
};

const greetLater = obj1.greet.bind(obj2);
greetLater(); // Вывод: Hello Universe!

const greetLater2 = obj1.greet.bind(obj1);
greetLater2(); // Вывод: Hello World!

Пример 3

const product = {
domain: "unarkhive.com",
showInfo(info, launch) {
console.log(`${this.domain} [${info}], Launch Date: ${launch}`);
}
};

const showUnarkhiveInfo = product.showInfo.bind(product, "Explore curated links across various categories, updated daily.");

showUnarkhiveInfo("Jul, 2024"); // Вывод: unarkhive.com [Explore curated links across various categories, updated daily.], Launch Date: Jul, 2024

Пример 4

function workingHours(hour, word) {
console.log(`${hour}, ${word}!`);
}

const morningGreet = workingHours.bind(null, "Opening");
const eveningGreet = workingHours.bind(null, "Closing");

morningGreet("09:00"); // Вывод: 09:00, Opening! (открытие)
eveningGreet("24:00"); // Вывод: 24:00, Closing! (закрытие)

Сравнение и общий пример

  • bind(): полезно для сохранения контекста для последующего использования, особенно в таких скриптах, как обработчики событий;
  • call() и apply(): используются для немедленного вызова функции с определенным контекстом; call() принимает аргументы по отдельности, а apply() — в виде массива.

Пример

const obj1 = {
first: 20,
second: 50
};

const obj2 = {
first: 60,
second: 120
};

function totalNumber(arg1, arg2) {
console.log(this.first + this.second + arg1 + arg2);
}

totalNumber(40); // NaN (не число)

totalNumber.call(obj1, 40, 60); // Вывод: 170

totalNumber.apply(obj1, [40, 60]); // Вывод: 170

const bindFunction = totalNumber.bind(obj2);

bindFunction(50, 110); // Вывод: 340

Заключение

Понимание и эффективное использование методов call()apply() и bind() в JavaScript могут значительно улучшить вашу способность управлять контекстами функций. Такое понимание гарантирует, что функции будут работать ожидаемо в различных объектах и скриптах, повышая надежность и гибкость кода.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Ozan Tekin: Call, Apply, and Bind Functions in JavaScript: Practical Guide

Предыдущая статьяEloquent: 40 методов ORM для разработчиков Laravel