Различия между Arrow Function, Function Declaration и Function Expression
В JavaScript существует несколько способов объявлять функции: Function Declaration, Function Expression и Arrow Function. Каждый из них имеет свои особенности в плане hoisting, использования this
, возможности быть конструктором, а также нюансов в синтаксисе и области применения.
Краткое сравнение в таблице
Характеристика | Function Declaration | Function Expression | Arrow Function |
---|---|---|---|
Синтаксис | function name() { ... } | const name = function() { ... } | const name = () => { ... } |
Hoisting | Полное (функция доступна до объявления) | Частичное (переменная всплывает, но функция инициализируется только в точке объявления) | Нет (при объявлении через const /let функция не всплывает) |
Собственный this | Да (зависит от вызова) | Да (зависит от вызова) | Нет (лексический this , наследуется из внешней области) |
arguments | Доступен | Доступен | Нет (использовать ...rest ) |
Использование с new | Да (может выступать как конструктор) | Да (если объявлена как обычная функция) | Нет (Arrow Function не может быть конструктором) |
Применение | Общие функции, конструкторы | Замыкания, колбэки | Однострочные функции, колбэки |
Детали и примеры
Hoisting (всплытие)
-
Function Declaration полностью всплывает. Это значит, что мы можем вызвать такую функцию даже до места её реального объявления в файле.
hello(); // "Hello from Declaration!" function hello() { console.log("Hello from Declaration!"); }
-
Function Expression c
var
всплывает как переменная (становится undefined до инициализации), но сама функция становится доступна только после строчки с присвоением. Если используется const или let, то никакого hoisting для функции, как готового значения, не происходит — вы не сможете вызвать функцию до её объявления.// Пример с var console.log(typeof sayHi); // "undefined" // sayHi(); // Ошибка: sayHi is not a function var sayHi = function () { console.log("Hello from Expression!"); };
-
Arrow Function объявляется обычно через
const
илиlet
, и поэтому не всплывает как готовая функция. Если попробовать вызвать стрелочную функцию до её объявления, будет ошибка.// greet(); // Ошибка: greet is not defined const greet = () => console.log("Hello from Arrow!");
Контекст this
-
У Function Declaration и Function Expression (если это не arrow) контекст
this
определяется способом вызова (или привязкой .call, .apply, .bind). -
У Arrow Function нет собственного
this
: он лексически заимствуется из области, в которой объявлена стрелочная функция.const user = { name: "Alice", sayHello: function() { console.log("Hello, I'm " + this.name); }, arrowHello: () => { console.log("Hello, I'm " + this.name); } }; user.sayHello(); // "Hello, I'm Alice" - this = user user.arrowHello(); // "Hello, I'm undefined" - this берётся из внешней области (глобальная / undefined)
arguments и оператор ...rest
-
Function Declaration и Function Expression имеют псевдомассив
arguments
, содержащий все аргументы функции. -
Arrow Function не имеет
arguments
, но можно использовать оператор...rest
для получения всех аргументов.function sumAll() { let total = 0; for (const arg of arguments) { total += arg; } return total; } const sumAllArrow = (...args) => { return args.reduce((acc, curr) => acc + curr, 0); };
Использование с new
- Только Function Declaration и Function Expression (не в формате стрелки) могут быть конструкторами.
- Arrow Function не может использоваться с
new
, так как у неё нет внутреннего механизма[[Construct]]
.