Урок 5 из 18
В прогрессе

5. Функции declaration/expression. Область видимости

Function Expression

Функция в JavaScript – это не магическая языковая структура, а особого типа значение.

Синтаксис, который мы использовали до этого, называется Function Declaration (Объявление Функции):

function sayHi() {
  alert( "Привет" );
}

Существует ещё один синтаксис создания функций, который называется Function Expression (Функциональное Выражение).

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

Это выглядит следующим образом:

let sayHi = function() {
  alert( "Привет" );
};

Здесь мы можем видеть переменную sayHi, получающую значение, новую функцию, созданную как function() { alert("Привет"); }.

Поскольку создание функции происходит в контексте выражения присваивания (с правой стороны от =), это Function Expression.

Обратите внимание, что после ключевого слова function нет имени. Для Function Expression допускается его отсутствие.

Здесь мы сразу присваиваем её переменной, так что смысл этих примеров кода один и тот же: «создать функцию и поместить её в переменную sayHi«.

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

Функция – это значение

Давайте повторим: независимо от того, как создаётся функция – она является значением. В обоих приведённых выше примерах функция хранится в переменной sayHi.

Мы даже можем вывести это значение с помощью alert:

 
 
function sayHi() {
  alert( "Привет" );
}

alert( sayHi ); // выведет код функции

Обратите внимание, что последняя строка не вызывает функцию, потому что после sayHi нет круглых скобок. Существуют языки программирования, в которых любое упоминание имени функции приводит к её выполнению, но JavaScript к таким не относится.

В JavaScript функция – это значение, поэтому мы можем обращаться с ней как со значением. Приведённый выше код показывает её строковое представление, которое является её исходным кодом.

Конечно, функция – это особое значение, в том смысле, что мы можем вызвать её как sayHi().

Но всё же это значение. Поэтому мы можем работать с ней так же, как и с другими видами значений.

Мы можем скопировать функцию в другую переменную:

 
 
function sayHi() {   // (1) создаём
  alert( "Привет" );
}

let func = sayHi;    // (2) копируем

func(); // Привет     // (3) вызываем копию (работает)!
sayHi(); // Привет    //     эта тоже все ещё работает (почему бы и нет)

Давайте подробно разберём всё, что тут произошло:

  1. Объявление Function Declaration (1) создаёт функцию и помещает её в переменную с именем sayHi.
  2. В строке (2) мы скопировали её значение в переменную func. Обратите внимание (ещё раз): нет круглых скобок после sayHi. Если бы они были, то выражение func = sayHi() записало бы результат вызова sayHi() в переменную func, а не саму функцию sayHi.
  3. Теперь функция может вызываться как sayHi(), так и func().

Мы также могли бы использовать Function Expression для объявления sayHi в первой строке:

let sayHi = function() { // (1) создаём
  alert( "Привет" );
};

let func = sayHi;
// ...

Всё будет работать так же.

Функции-«колбэки»

 

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

Давайте напишем функцию ask(question, yes, no) с тремя параметрами:

question
Текст вопроса
yes
Функция, которая будет вызываться, если ответ будет «Yes»
no
Функция, которая будет вызываться, если ответ будет «No»

Наша функция должна задать вопрос question и, в зависимости от того, как ответит пользователь, вызвать yes() или no():

 
 
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( "Вы согласны." );
}

function showCancel() {
  alert( "Вы отменили выполнение." );
}

// использование: функции showOk, showCancel передаются в качестве аргументов ask
ask("Вы согласны?", showOk, showCancel);

На практике подобные функции очень полезны. Основное отличие «реальной» функции ask от примера выше будет в том, что она использует более сложные способы взаимодействия с пользователем, чем простой вызов confirm. В браузерах такие функции обычно отображают красивые диалоговые окна. Но это уже другая история.

Аргументы showOk и showCancel функции ask называются функциями-колбэками или просто колбэками.

Ключевая идея в том, что мы передаём функцию и ожидаем, что она вызовется обратно (от англ. «call back» – обратный вызов) когда-нибудь позже, если это будет необходимо. В нашем случае, showOk становится колбэком для ответа «yes», а showCancel – для ответа «no».

Мы можем переписать этот пример значительно короче, используя Function Expression:

 
 
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  "Вы согласны?",
  function() { alert("Вы согласились."); },
  function() { alert("Вы отменили выполнение."); }
);

Здесь функции объявляются прямо внутри вызова ask(...). У них нет имён, поэтому они называются анонимными. Такие функции недоступны снаружи ask (потому что они не присвоены переменным), но это как раз то, что нам нужно.

Подобный код, появившийся в нашем скрипте выглядит очень естественно, в духе JavaScript.

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

 

Существует ещё один очень простой и лаконичный синтаксис для создания функций, который часто лучше, чем Function Expression.

Он называется «функции-стрелки» или «стрелочные функции» (arrow functions), т.к. выглядит следующим образом:

let func = (arg1, arg2, ...argN) => expression;

Это создаёт функцию func, которая принимает аргументы arg1..argN, затем вычисляет expression в правой части с их использованием и возвращает результат.

Другими словами, это сокращённая версия:

let func = function(arg1, arg2, ...argN) {
  return expression;
};

Область видимости

 

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

Базово разделить область видимости можно на глобальную и локальную. Глобальная – это область видимости сразу всей программы. А локальная – область видимости каждой отдельной части кода в программе, например, внутри функции.

Пример

Представим, что наша программа состоит из двух переменных и одной функции, которую мы разбирали в Уроке 4:

let someVar = 20;
let someOtherVar = 30;
 function sum (a, b) {
   let result = a + b;
   return result;
}

В глобальную область видимости войдут переменные someVar и someOtherVar, а также функция sum.

В локальной видимости находится то, что указано внутри функции sum: два параметра a и b, а также переменная result.

Добавим ещё одну функцию:

function someFn (a, b, c ,d) {
    let var1 = 10;
    let var2 = a+ b + c + d + var1;
    return var2
}

Теперь в глобальную область видимости добавилась и функция someFn, а в функции someFn образовалась собственная локальная область видимости, которая состоит из параметров a, b, c, d и двух переменных var1 и var2.

Задание:

  1. Создайте страницу, которая спрашивает три коэффициента квадратного уравнения (a,b,c) 
  2. Выведите ответ в модальное окно или консоль.

Используйте формулу: ax2 + bx + c = 0