В этом уроке вы узнаете, когда не нужно использовать стрелочные функции в ES6 JavaScript.
У стрелочной функции нет собственного значения this
и объекта arguments
. Поэтому его не следует использовать в качестве обработчика событий, метода литерала объекта, метода-прототипа или когда у вас есть функция, использующая объект arguments
.
1) Обработчики событий
Предположим, что у вас есть следующее текстовое поле ввода:
<input type="text" name="username" id="username" placeholder="Enter a username">
И вы хотите показывать приветственное сообщение, когда пользователи вводят свои имена пользователей. Ниже показан элемент <div>, который будет отображать приветственное сообщение:
<div id="greeting"></div>
Как только пользователи вводят свои имена пользователей, вы фиксируете текущее значение ввода и обновляете его до элемента <div>:
const greeting = document.querySelector('#greeting'); const username = document.querySelector('#username'); username.addEventListener('keyup', () => { greeting.textContent = 'Hello ' + this.value; });
Однако при выполнении кода вы получите следующее сообщение независимо от того, что вы введете:
Hello undefined
Это означает, что this.value
в обработчике событий всегда возвращает значение undefined
.
Как упоминалось ранее, стрелочная функция не имеет собственного значения this
. Она использует значение this
объемлющей лексической области. В приведенном выше примере функция со стрелкой this
in ссылается на глобальный объект.
В веб-браузере глобальным объектом является window
. Объект window
не имеет свойства value
. Поэтому движок JavaScript добавляет свойство value к объекту window
и устанавливает для него значение undefined
.
Чтобы решить эту проблему, вам нужно использовать обычную функцию. this
значение будет привязано к элементу <input>, который запускает событие.
username.addEventListener('keyup', function() { input.textContent = 'Hello ' + this.value; });
2) Методы объекта
См. следующий объект counter
:
const counter = { count: 0, next: () = > ++this.count, current: () = > this.count };
Объект counter
имеет два метода: current()
и next()
. Метод current()
возвращает текущее значение счетчика, а метод next()
возвращает следующее значение счетчика.
Ниже показано следующее значение счетчика, которое должно быть равно 1:
console.log(counter.next());
Однако он возвращает NaN
.
Причина в том, что когда вы используете стрелочную функцию внутри объекта, она наследует значение this
от объемлющей лексической области видимости, которая в данном примере является глобальной областью видимости.
this.count
внутри метода next()
эквивалентен window.count
(в веб-браузере).
По умолчанию значение window.count
не undefined
, поскольку объект window
не имеет свойства count
. Метод next()
добавляет единицу к undefined
, что приводит к NaN
.
Чтобы исправить это, вы используете обычные функции в качестве метода литерала объекта следующим образом:
const counter = { count: 0, next() { return ++this.count; }, current() { return this.count; } };
Теперь вызов метода next()
вернет единицу, как и ожидалось:
console.log(counter.next()); // 1
3) Методы-прототипы
См. следующий объект Counter
, использующий шаблон prototype
:
function Counter() { this.count = 0; } Counter.prototype.next = () => { return this.count; }; Counter.prototype.current = () => { return ++this.next; }
Значение this
в этих методах next()
и current()
ссылается на глобальный объект. Поскольку вы хотите, чтобы this
значение внутри методов ссылалось на объект Counter
, вместо этого вам нужно использовать обычные функции:
function Counter() { this.count = 0; } Counter.prototype.next = function () { return this.count; }; Counter.prototype.current = function () { return ++this.next; }
4) Функции, использующие объект arguments
Стрелочные функции не имеют объекта arguments
. Поэтому, если у вас есть функция, которая использует объект arguments
, вы не можете использовать функцию стрелки.
Например, следующая функция concat()
не будет работать:
const concat = (separator) => { let args = Array.prototype.slice.call(arguments, 1); return args.join(separator); }
Вместо этого вы используете обычную функцию, подобную этой:
function concat(separator) { let args = Array.prototype.slice.call(arguments, 1); return args.join(separator); }
Заключение
- Стрелочная функция не имеет собственного значения
this
. Вместо этого она использует значениеthis
объемлющей лексической области. У стрелочной функции также нет объектаarguments
. - Избегайте использования функции стрелки для обработчиков событий, методов объекта, методов прототипа и функций, использующих объект
arguments
.