Клавиша / esc

Стрелочные функции

Более компактная запись, чем у обычных функций.

Время чтения: меньше 5 мин

Кратко

Скопировано

Стрелочная функция это короткая запись функционального выражения (function expression) без собственных привязок this, arguments и super.

Как пишется

Скопировано

Если функция принимает только один аргумент, круглые скобки вокруг него можно не ставить. Если тело функции состоит из одного выражения, оператор return также необязателен.

        
          
          const divider = n => n / 2
          const divider = n => n / 2

        
        
          
        
      

Если тело функции содержит несколько выражений, оберните их в фигурные скобки. Здесь оператор return нужен, так как функция что-то возвращает.

        
          
          const sayHello = (name) => {  const greeting = `Hello ${name}`  return greeting}
          const sayHello = (name) => {
  const greeting = `Hello ${name}`
  return greeting
}

        
        
          
        
      

Как понять

Скопировано

Стрелочные функции пишутся короче:

        
          
          // Обычная функцияfunction divider(n) {  return n / 2}// Стрелочная функцияconst divider = n => n / 2
          // Обычная функция
function divider(n) {
  return n / 2
}

// Стрелочная функция
const divider = n => n / 2

        
        
          
        
      

У стрелочных функций нет своих привязок для arguments, super, this или new.target. Значения этих ключевых слов привязываются к внешнему лексическому окружению.

Использование call() или apply() никак не влияет на стрелочные функции.

        
          
          class Person {  constructor(name) {    this.name = name  }  sayName() {    console.log(this.name)  }  sayNameWithArrowFunction = () => {    console.log(this.name)  }}const alex = new Person('Alex')console.log(alex.sayName())// Alexconsole.log(alex.sayNameWithArrowFunction())// Alexconst den = new Person('Den')console.log(alex.sayName.call(den))// Denconsole.log(alex.sayNameWithArrowFunction.call(den))// Alex, т. к. не изменить контекст
          class Person {
  constructor(name) {
    this.name = name
  }

  sayName() {
    console.log(this.name)
  }

  sayNameWithArrowFunction = () => {
    console.log(this.name)
  }
}

const alex = new Person('Alex')
console.log(alex.sayName())
// Alex

console.log(alex.sayNameWithArrowFunction())
// Alex

const den = new Person('Den')
console.log(alex.sayName.call(den))
// Den

console.log(alex.sayNameWithArrowFunction.call(den))
// Alex, т. к. не изменить контекст

        
        
          
        
      

В теле стрелочных функций arguments будет ссылаться на arguments из внешней лексической области:

        
          
          function f() {  const arrowFunction = () => {    console.log(arguments)  }  arrowFunction('стрелочная функция')}f('обычная функция')//  { 0: 'обычная функция', length: 1 }
          function f() {
  const arrowFunction = () => {
    console.log(arguments)
  }

  arrowFunction('стрелочная функция')
}

f('обычная функция')
//  { 0: 'обычная функция', length: 1 }

        
        
          
        
      

У стрелочных функций нет свойств сonstructor и prototype:

        
          
          const arrowFunction = () => {}console.log(arrowFunction.prototype)// undefined
          const arrowFunction = () => {}
console.log(arrowFunction.prototype)
// undefined

        
        
          
        
      

И, как следствие, стрелочные функции не могут быть использованы как конструктор. Их нельзя использовать с оператором new.

        
          
          const arrowFunction = () => {}console.log(new arrowFunction())// TypeError: arrowFunction is not a constructor
          const arrowFunction = () => {}
console.log(new arrowFunction())
// TypeError: arrowFunction is not a constructor

        
        
          
        
      

Стрелочные функции нельзя использоваться как генераторы. Ключевое слово super внутри стрелочных функций ссылается на super из внешнего лексического окружения, а не на super родительского класса.

До появления стрелочных функций возникали проблемы с использованием this внутри функций-колбэков. Посмотрите на пример с setTimeout.

        
          
          const obj = {  count: 10,  doSomethingLater() {    setTimeout(function () {      // Тут this ссылается на объект Window      this.count++      console.log(this.count)    }, 1000)  },};obj.doSomethingLater()// "NaN"
          const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(function () {
      // Тут this ссылается на объект Window
      this.count++
      console.log(this.count)
    }, 1000)
  },
};

obj.doSomethingLater()
// "NaN"

        
        
          
        
      

В колбэк-функции setTimeout, this указывает на объект Window, а не на obj, поэтому значение this.count оказывается неверным.

Поэтому приходилось использовать различные методы для передачи контекста внутрь колбэка.

Например, при помощи bind(this):

        
          
          const obj = {  count: 10,  doSomethingLater() {    setTimeout(function () {      this.count++      console.log(this.count)    }.bind(this), 1000)  },}obj.doSomethingLater()// 11
          const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(function () {
      this.count++
      console.log(this.count)
    }.bind(this), 1000)
  },
}

obj.doSomethingLater()
// 11

        
        
          
        
      

Также использовался хак с переменной that, где сохранялся контекст this, и внутри колбэка уже использовалась эта переменная:

        
          
          const obj = {  count: 10,  doSomethingLater() {    const that = this    setTimeout(function () {      that.count++      console.log(that.count)    }, 1000)  },}obj.doSomethingLater()// 11
          const obj = {
  count: 10,
  doSomethingLater() {
    const that = this
    setTimeout(function () {
      that.count++
      console.log(that.count)
    }, 1000)
  },
}

obj.doSomethingLater()
// 11

        
        
          
        
      

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

        
          
          const obj = {  count: 10,  doSomethingLater() {    setTimeout(() => {      this.count++      console.log(this.count)    }, 1000)  },}obj.doSomethingLater()// 11
          const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(() => {
      this.count++
      console.log(this.count)
    }, 1000)
  },
}

obj.doSomethingLater()
// 11