Function Expression и функция как значение
До сих пор мы объявляли функции отдельно – function greet(name) {...} – а затем вызывали их. Но в JavaScript есть важная идея: сама функция тоже является значением.
В переменной можно хранить число или строку:
const count = 42;const title = 'Курс';И точно так же – функцию:
const greet = function (name) { return `Привет, ${name}!`;};Такая запись называется Function Expression, или функциональное выражение:
Запись отличается от привычного объявления тремя деталями. Функция стоит справа от знака = и ведёт себя как обычное значение:
Имя после function можно не писать – такую функцию называют анонимной: чтобы вызвать её, достаточно имени переменной, в которой она лежит. Написать имя никто не запрещает, но в Function Expression оно обычно не нужно:
В конце ставим ;, потому что вся конструкция – это объявление переменной greet, такое же, как объявление count:
Функцию создали как значение и положили в переменную greet. Теперь greet можно вызывать точно так же, как функции из прошлых уроков:
console.log(greet('Ира'));console.log(greet('Макс'));Запись const greet = function () {...}; можно мысленно читать так: «создай функцию и сохрани её в greet». Это очень похоже на обычное присваивание:
const count = 42;const title = 'Курс';const greet = function () { /* ... */ };Различается только содержимое. В greet лежит не результат работы функции, а ссылка на саму функцию – своего рода адрес, по которому её можно найти. Поэтому функцию можно вызвать, сохранить под другим именем или передать куда-нибудь дальше.
Значения, которые хранятся в переменной вот так, «по ссылке», называют ссылочными – подробно разберём их, когда познакомимся с объектами:
Убедиться, что в greet лежит именно функция, можно напрямую – напечатать переменную:
const greet = function (name) { return `Привет, ${name}!`;};console.log(greet);greet и greet() – не одно и то же
Круглые скобки меняют смысл записи. greet – это сама функция как значение. greet() – вызов этой функции и результат её работы.
Посмотрим на разницу по шагам:
Главное здесь – строка const twice = double;. Скобок после double нет, поэтому функцию мы не вызываем. Мы берём саму функцию и сохраняем её ещё в одной переменной.
Теперь и double, и twice ведут к одной и той же функции. Вызвать её можно через любую из них:
const greet = function () { console.log('Привет!');};const hello = greet;greet();hello();Теперь обе переменные указывают на одну и ту же функцию:
И это не просто удобная картинка. greet и hello действительно содержат ссылку на одну и ту же функцию – поэтому при строгом сравнении получим true:
const greet = function () { console.log('Привет!');};const hello = greet;console.log(greet === hello);true означает, что в обеих переменных находится одна и та же функция, а не две одинаковые копии.
Теперь мы знаем два способа определить функцию. Поставим их рядом:
function greet(name) { return `Привет, ${name}!`;}const greet = function (name) { return `Привет, ${name}!`;};После создания пользоваться обеими функциями можно одинаково: greet('Ира'). Но есть важное различие – с какого момента ими уже можно пользоваться.
Function Declaration доступна до строки объявления
sayHi();function sayHi() { console.log('Привет!');}Хотя вызов стоит выше функции, код работает. Перед выполнением программы JavaScript заранее подготавливает объявления функций, поэтому к моменту первой строки sayHi уже доступна.
Посмотрим по шагам:
Вот что JavaScript подготовил к моменту вызова:
Function Expression доступна только после присваивания
sayHi();const sayHi = function () { console.log('Привет!');};С const sayHi = ... ситуация другая. JavaScript заранее знает, что переменная sayHi существует, но её значение станет доступно только тогда, когда выполнение дойдёт до строки присваивания. Поэтому вызов раньше этой строки заканчивается ReferenceError:
Зачем тогда нужен Function Expression?
После создания Function Declaration и Function Expression ведут себя во многом одинаково: обе функции можно вызывать, сохранять в других переменных и передавать дальше.
Особенность Function Expression в другом: функцию можно создать прямо там, где программе нужно значение. Например, сохранить её в переменную или сразу передать другой функции.
Последний вариант в JavaScript встречается постоянно:
runTwice(function () { console.log('Привет!');});Здесь функция создана прямо внутри вызова runTwice(...) – отдельное имя ей даже не понадобилось.
Что значит «передать функцию» и зачем это вообще нужно – разберём в следующем уроке.
// теперь вы знаете
- Function Expression позволяет создать функцию и сохранить её как обычное значение в переменной
- Функцию можно хранить в переменной и сохранить под другим именем: обе переменные будут указывать на одну функцию
- greet – сама функция, greet() – её вызов и результат этого вызова
- Function Declaration можно вызвать раньше строки объявления; Function Expression становится доступна через переменную только после выполнения присваивания
Что лежит в переменной greet после этой строки?
const greet = function () {console.log('Привет!');};
Что окажется в переменных twice и result?
function double(x) {return x * 2;}const twice = double;const result = double(5);
Что напечатает программа?
const greet = function () {console.log('Привет!');};const hello = greet;hello();console.log(greet === hello);
Что произойдёт здесь?
sayHi();function sayHi() {console.log('Привет!');}
Что произойдёт?
say();const say = function () {console.log('привет');};
Какие вызовы сработают?
hello();function hello() {console.log('hello');}bye();const bye = function () {console.log('bye');};
Выбери все верные варианты