Выразительный JavaScript | страница 26
А что будет, если мы поместим объявление функции внутрь условного блока или цикла? Не надо так делать. Исторически разные платформы для запуска JavaScript обрабатывали такие случаи по разному, а текущий стандарт языка запрещает так делать. Если вы хотите, чтобы ваши программы работали последовательно, используйте объявления функций только внутри других функций или основной программы.
>function example() {
> function a() {} // Нормуль
> if (something) {
> function b() {} // Ай-яй-яй!
> }
>}
Стек вызовов
Полезным будет присмотреться к тому, как порядок выполнения работает с функциями. Вот простая программа с несколькими вызовами функций:
>function greet(who) {
> console.log("Привет, " + who);
>}
>greet("Семён");
>console.log("Покеда");
Обрабатывается она примерно так: вызов >greet
заставляет проход прыгнуть на начало функции. Он вызывает встроенную функцию >console.log
, которая перехватывает контроль, делает своё дело и возвращает контроль. Потом он доходит до конца greet, и возвращается к месту, откуда его вызвали. Следующая строчка опять вызывает >console.log
.
Схематично это можно показать так:
>top
> greet
> console.log
> greet
>top
> console.log
>top
Поскольку функция должна вернуться на то место, откуда её вызвали, компьютер должен запомнить контекст, из которого была вызвана функция. В одном случае, >console.log
должна вернуться обратно в >greet
. В другом, она возвращается в конец программы.
Место, где компьютер запоминает контекст, называется стеком. Каждый раз при вызове функции, текущий контекст помещается наверх стека. Когда функция возвращается, она забирает верхний контекст из стека и использует его для продолжения работы.
Хранение стека требует места в памяти. Когда стек слишком сильно разрастается, компьютер прекращает выполнение и выдаёт что-то вроде “stack overflow” или “too much recursion”. Следующий код это демонстрирует – он задаёт компьютеру очень сложный вопрос, который приводит к бесконечным прыжкам между двумя функциями. Точнее, это были бы бесконечные прыжки, если бы у компьютера был бесконечный стек. В реальности стек переполняется.
>function chicken() {
> return egg();
>}
>function egg() {
> return chicken();
>}
>console.log(chicken() + " came first.");
>// → ??
Необязательные аргументы
Следующий код вполне разрешён и выполняется без проблем:
>alert("Здрасьте", "Добрый вечер", "Всем привет!");
Официально функция принимает один аргумент. Однако, при таком вызове она не жалуется. Она игнорирует остальные аргументы и показывает «Здрасьте».