JavaScript: преимущества стрелочных функций

Возможно, вы не знаете, что это одно из основных различий между обычными и стрелочными функциями ES6 в JavaScript.

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

  • Когда нам следует использовать обычные функции, а когда стрелочные функции?
  • В чем разница между обычными функциями и стрелочными функциями?
  • Можем ли мы использовать одно или другое во всех ситуациях для единообразия?

Проведя небольшое исследование, я обнаружил, что обычные функции и стрелочные функции в определенных обстоятельствах фактически не взаимозаменяемы. Помимо синтаксиса, обычные функции и стрелочные функции имеют еще одно важное отличие, которое заключается в способе привязки ключевого слова this.

Давайте рассмотрим очень простой пример. Предположим что, у нас есть следующий объект JavaScript:

const obj1 = {
	  fullName: 'Object 1',
	  color: 'red',
	  print: function() {
	    console.log(`${this.fullName} is ${this.color}`);
	  }
	};
	

	obj1.print(); // Object 1 is red

У нас есть метод print для obj1, который выводит строку в консоль. Результат - то, что, как мы и ожидали, this в методе print ссылается на сам obj1.

Теперь давайте создадим еще один объект с немного другим методом print:

const obj2 = {
	  fullName: 'Object 2',
	  color: 'blue',
	  print: function() {
	    setTimeout(function() {
	      console.log(`${this.fullName} is ${this.color}`);
	    }, 1000);
	  }
	};
	

	obj2.print(); // undefined - is undefined

Теперь метод print будет выводить полученную строку только через одну секунду из-за setTimeout. Но почему undefined is undefined вместо вывода Object 2 is blue?

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

В приведенном выше фрагменте кода в строке 5 анонимная функция, объявленная с использованием обычного объявления функции, передается как обратный вызов для setTimeout. Затем два this в строке 6 будут ссылаться на объект, которому принадлежит метод setTimeout, который переходит в объект window.

Поскольку свойства fullName и color не существуют в объекте window, результирующая строка возвращает undefined is undefined.

Как мы можем сделать так, чтобы два this в строке 6 ссылались на obj2? На этот раз давайте объявим функцию обратного вызова в строке 5, используя синтаксис стрелочной функции ES6:

const obj2 = {
	  fullName: 'Object 2',
	  color: 'blue',
	  print: function() {
	    setTimeout(() => {
	      console.log(`${this.fullName} is ${this.color}`);
	    }, 1000);
	  }
	};
	

	obj2.print(); // Object 2 is blue

Это работает! Так какова же теория этого изменения?

Что ж, оказывается, что объявление стрелочной функции создает то, что мы называем лексической областью видимости. Это означает, что два this в строке 6 будут ссылаться не на свой непосредственный родительский объект, а на вызывающий, который вызвал функцию, содержащую их.

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

Заключение

Я надеюсь, что эта статья объяснила необходимые концепции и помогла вам разобраться с путаницей. Ключевое слово this в JavaScript целая тема сама по себе, и есть много дискуссий об этом, но документация MDN является хорошей отправной точкой для дальнейших исследований.

Пожалуйста, оставьте ваши комментарии по текущей теме статьи. Мы очень благодарим вас за ваши комментарии, отклики, лайки, дизлайки, подписки!

Пожалуйста, опубликуйте ваши мнения по текущей теме материала. За комментарии, лайки, дизлайки, отклики, подписки низкий вам поклон!

Вадим Дворниковавтор-переводчик статьи «JavaScript: The Good Parts of Arrow Functions»