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 является хорошей отправной точкой для дальнейших исследований.