Титры к видео уроку - "Функции"

Ссылка на полный видео урок

Функции – это блок кода, который можно многократно вызывать для выполнения. Функция может принимать аргументы и возвращать значения. Я думаю, что многие из слушателей этого видеокурса сталкивались с такими понятиями как функции и процедуры. На всякий случай давайте мы попробуем еще раз с самого начала объяснить и понять, как работают функции, какое их назначение в программном коде. Функция по сути является основным строительным блоком любого приложения. Если вы посмотрите на этот слайд, то вот этот прямоугольник посредине слайда, он у нас символизируем функцию, то есть это некий черный ящик. Мы даем ему какую-то информацию на вход, в этом черном ящике происходят какие-то операции и что-то появляется на выходе, какой-то результат. Вот получается, мы в функцию передаем сейчас, вот эта иконка символизирует у нас один байт информации, вот со значением один в двоичной системе исчисления. Вот мы в функцию передали это значение, вот эти колесики, они символизируют какие-то действия, происходящие внутри функции, то есть функция произвела какие-то вычисления, что-то произошло с этим значением, и в итоге функция на выход дала какое-то новое значение. Бывают функции, которые принимают данные и выдают какой-то результат. Бывают функции, которые ничего не принимают и выдают какой-то результат. Бывают функции, которые ничего не принимают и ничего не выдают. Бывают функции, которые что-то принимают, но ничего не возвращают. То есть, есть несколько разновидностей функций, мы сейчас их в коде всех с вами разберем. Но перед тем, как переходить к коду, давайте попробуем понять назначение функций на каком-нибудь простом, жизненном примере. Представьте, что вам, в вашем приложении нужно описать процесс заварки чая. Вам нужно будет в JavaScript сценарии несколько раз в разных частях программы вашей выполнять заварку чая. Из чего состоит заварка чая? Первое – нужно пойти на кухню. Второе – нужно взять чашку и засыпать туда сахар и чай. Третья операция – закипятить воду. Четвертая – залить воду в чашку. Вот 4 операции и чай готов. Если вам нужно в вашем приложении чай заваривать 10 раз, вот вам придется в 10 разных частях программы вызвать 4 инструкции для того, чтобы заварить чай. При этом вам нужно следить, чтобы вы не напутали с последовательностью инструкций, потому что если вы в начале зальете воду, потом закипятите ее, это уже будет не совсем чай, неправильно он будет сделан. Получается, что в тех ситуациях, когда у нас есть несколько инструкций, какой-то блок кода, который повторяется в разных частях программы, вот этот блок кода можно превратить в функцию. Например, вот эти 4 инструкции, для заварки чая, их можно вынести в функцию и дать функции имя «Заварить чай». А те части программы, в которых мы раньше пытались заваривать чай, используя 4 инструкции, 4 команды последовательные, вот эти 4 команды можно удалить и вместо них установить запуск функции «заварка чая». Я верю, что после просмотра примеров, назначение функций всем будет понятней.

Давайте сейчас посмотрим второй слайд, посмотрим, как именно функция определяется в JavaScript коде, потом перейдем в Visual Studio и посмотрим на несколько первых примерах. Когда мы хотим определить в коде функцию, первое, что мы должны сделать – это использовать специальное ключевое слово. Слова function. Наличие этого слова в коде указывает, что мы сейчас создаем новую функцию, или объявляем функцию. После слова function в большинстве случаев следует имя. В некоторых ситуациях имя не указывается, мы рассмотрим такие варианты функций, но сейчас на слайде вы видите, что сразу после function, тут же идет фраза, литерал, который будет указывать имя функции, обычно функцию называют не так, как на нашем слайде, myFunction – это имя, которое ничего не означает. По имени не можем понять, а что именно делает функция. Хорошее имя для функции – это глагол, описывающею что именно функция будет выполнять, когда мы ее вызовем. Например, функция будет называются getUserName. Сразу же понятно назначение функции. Если мы ее запустим, то она отдаст нам имя пользователя. Или спросит имя у пользователя, или спросит имя у пользователя, или получит его с каких-то внутренних переменных. Другой вариант функции – Calculate, CalculateSum, например, то есть посчитать сумму. Понятно, что если мы эту функцию запустим, то получим сумму каких-то значений. После имени функции, у нас установлены параметры, параметры – это то, что функция принимает для обработки. Если нашей функции при запуске необходимы какие-то значения, эти значения функции могут быть переданы с помощью параметров. Подробней с параметрами мы познакомимся с вами уже в примерах.

Давайте сейчас посмотрим первые примеры использования функции в Visual Studio. Значит, как мы уже посмотрели на слайдах, определение функции всегда начинается с ключевого слова function. Вот на строке 21 мы создаем функцию, создаем приложение, создаем строительный блок, который будем потом неоднократно использовать. Мы указали ключевое слово, далее мы указали имя функции – MyFirstFunction(). Так как эта функция не принимает никаких входящих данных, она не должна производить расчеты над какими-то значениями, мы просто после имени ставим круглые скобочки. Это означает, что функция не принимает никаких параметров. И далее в теле функции мы выполняем три инструкции, в тело документа выводим сообщение «Hello from MyFirstFunction!, How are you?, Goodbye!». Вот эти три строчки появляться в документе если мы запустим эту функцию. Мы сейчас просто создали функцию, то есть это просто заготовка, которую потом нужно вызвать, выполнить. Получается, когда интерпретатор, когда браузер дойдет до 21 строки. Существует такая функция, он не будет выполнять этот код, потому что определение функции, это просто создание инструкций, которые в будущем кто-то начнет использовать. Так же в нашем примере есть еще одна функция, на 27 строке, эта функция называется MySecondFunction(), и она выводит только одно сообщение «Hello from MySecondFunction!». Это все что она делает. Точно так же, как и предыдущая функция, это всего лишь объявление. То есть это блок кода, который не будет выполнятся до тех пор, пока мы не обратимся к функции и не запустим ее, не вызовем функцию. Значит 21-22 строка – мы объявили функцию. Теперь как мы этими функциями пользуемся. 33 строчка. Мы берем имя функции MyFirstFunction() уже без ключевого слова function, только имя и круглые скобочки. Когда мы используем такой синтаксис – имя функции + ее параметры, это означает, что мы обращаемся к функции и вот на строе 33, как только мы выполним эту операцию, это означает, что с 33 строки мы перепрыгиваем на строку 21. Выполняем инструкции на 22, 23, 24 строчке, и потом, когда мы эти инструкции до конца выполняем, мы возвращаемся обратно, перепрыгиваем на 33 строку и продолжаем выполнять инструкции, которые идут вот в этой части кода. Выполняем 35 строчку, вводим горизонтальную линию. Потом на 37 строчке мы видим, что мы взываем вторую функцию MySecondFunction(). То есть на 37 строке мы прыгаем на строчку 27, заходим в тело функции, вот операторные скобки, выполняем инструкцию, которая здесь заложена. Как только мы до конца выполняем все инструкции, заложенные в функции, мы возвращаемся обратно в ту точку, где функция изначально была запущена. Давайте попробуем проверить, что получится. Вот вы видите, первый раз мы на 33 строке вызвали функцию и отобразились те сообщения, которые заложены внутри этой функции, вот все эти инструкции, код весь этот выполнился. Потом 35 строчка, мы вывели горизонтальную линию. И строка 37 мы еще раз запустили функцию, уже вторую функцию и вот увидели ее результат. Если мы хотим несколько раз повторить вот этот блок кода, несколько раз вывести эти три сообщения, можем взять и просто продублировать вызов функции. Вот мы сейчас три раза запускаем MyFirstFunction(), то есть в приложении, на 33 строке мы пригнем на строку 21, выполним все что заложено в функции, вернемся обратно сюда. Перейдем на 34 строчку и увидим, что на ней опять происходит вызов функции. На 34 строке мы пригнем на 21 строчку, выполним все, что заложено в функцию и вернемся обратно на 34. На 35 опять пригнем в функцию, выполним все, что заложено и вернемся на 35. То есть каждый раз, когда мы вызываем функцию, мы производим переход в другую часть программы, выполняем инструкции, заложенные в этой другой части программы и возвращаемся обратно, где функция была изначально запущена. Давайте сейчас запустим и проверим, первый раз вызвалась наша функция, второй раз и третий раз. Вот пример, который я приводил с заваркой чая. Вместо того, чтобы здесь дублировать инструкции заварки чая, мы эти инструкции вынесли в отдельную функцию и каждый раз, когда нам хочется чая, мы берем и запускаем функцию сделать чай и не задумываемся о тех шагах, которые нужно выполнить, для того, чтобы появилась чашка чая. Перед тем, как переходить к следующим примерам, хочу, чтобы мы еще посмотрели, как можно пользоваться отладчиком и посмотреть, как функции работают именно под отладчиком. Лично мне удобней пользоваться отладчиком, который работает в Google Chrome, но как мы уже разбирали на прошлых уроках, если вы возьмете Firefox, например, с установленными Fireback флаером, или Internet Explorer, или Opera, во всех современных браузерах есть инструменты разработчика, поэтому просто выберете тот браузер, которым вам пользоваться нравится больше всего и в нем попробуйте разобраться с инструментами разработчика. Если мы сейчас запустим этот пример, в Chrome, если мы нажимаем на F12 в браузере это открывает панель разработчика. Вот панель разработчика, нас интересует сейчас вкладочка source. Вот когда вы впервые запустите свое приложение, вы увидите, что вот на этой вкладочке ничего нету, будет пусто, никаких исходных кодов текущего документа отображаться не будет. Если нажать по этой кнопочки showNavigator, то вы увидите те сценарии, которые доступны сейчас в текущем документе. Мы выбираем сейчас сам HTML документ, переходим в его исходный код, находим интересующею для нас функцию, вот мы хотим начать отладку с 33 строки. Ставим здесь breakpoint. Мы на прошлых занятиях разбирали с вами что такое breakpoint. Поставили breakpoint. Для того, чтобы теперь этот breakpoint сработал, чтобы эта точка остановила код и показала нам пошаговое выполнение скрипта, мы можем сейчас обновить страницу, видите сейчас вот это синий блок, красная стрелочка, которая находится рядом с ним, эта стрелочка символизирует ту часть кода, которую сейчас браузер выполняет. Вот сейчас мы возьмем с вами и если будем нажимать на кнопку F10 или на эту иконку, это означает, что мы переходи пошагово, построчно. Просто выполняем все инструкции. Если мы будем нажимать на кнопку F11 или на эту иконку, это будет означать, что при вызове функции мы будем переходить внутрь функции и смотреть, что будет происходить в самой функции. Вот если мы сейчас нажмем на F11, так как вот здесь мы взываем функцию myFunction, мы должны перейти внутрь функции, выполнить весь код, который находится в функции и вернутся обратно на 33 строчку. Давайте попробуем. Нажимаем на F11, видите мы попали внутрь функции, на строчку 22. Нажимаем еще раз F11, еще раз, и вот когда мы закончим операцию на 24 строке, мы вернемся в ту часть кода, в которой функцию изначально вызвали. Нажимаем еще раз F11 и вот видите мы вернулись на строчку 34 из-за функции, которую изначально запустили. Если сейчас еще раз нажать F11. Так как на 34 строке опять запускается функция, мы вернемся в тело функции и выполним то что находится в теле функции. Нажимаем F11, попадаем в функцию, выполняем код, который заложен в функции, видите, код у нас выводится сразу же в самом документе по мере его выполнения, выполнили функцию, вернулись в ту часть кода, где функция запускалась. Следующая функция, нажимаем F11, попадаем в тело функции, и вот так далее. Вот если вы не понимаете, как работает сценарий, если вы хотите найти ошибки в сценарии, рекомендую пользоваться отладчиком, он всегда помогает сэкономить время и быстро найти ту часть кода, с которой что-то у вас работает некорректно.

В следующем примере мы увидим, как в функции можно использовать переменные, которые доступны в области видимости, глобальной области видимости. Подробней о областях видимости мы сейчас с вами поговорим, а вот пока разберем данный пример. То есть в этом примере мы разберем, что функции могут работать с переменными в своем теле. Сейчас у нас есть 2 функции, на 22 строчке ask и на 28 функция say. То есть «спросить» и «сказать». Функция ask будет запускать ряд prompt функций, то есть функция prompt, это функция, которая уже определена в браузере. То есть если вот эта функция, это основная функция, то функция prompt находится где-то в браузере, задача этой функции показать диалоговое окошко, получить от пользователя данные, обработать эти данные и вернуть в наше приложение, вернуть нашему сценарию уже. Если кто-то запустит функцию ask в нашем коде, то вначале мы получим от пользователя имя, потом фамилию, потом возраст. И эти полученные данные запишем в переменную name, sname и age. Переменные, которые мы используем в функции ask обвялены выше, на 18, 19, 20 строчке. Вот эти переменные объявлены здесь и соответственно они могут быть использованы как внутри функции ask, так и внутри функции say. Видите, что функция say будет последовательно отображать вначале имя, потом фамилию, потом возраст и выводить эту информацию в тело документа. Но как мы уже с вами обсуждали, определение функции не значит, что эти функции будут работать, просто определив функцию, мы определили строительный блок в нашем приложении. Тут этот строительный блок должен использовать, для того чтобы код в функции запустился. И вот на 37 строке мы первый раз вначале запускаем функцию ask, чтобы попросить пользователя заполнить значениями переменные. А второй раз на 38 строчке мы запускаем функцию say, чтобы значения, которые находятся в переменных отобразились пользователю на экран. Давайте запустим пример и проверим. Первое – введите свое имя, фамилию и возраст. Вот значения, которые мы ввели в поля ввода, вот они отобразились у нас на экране.

В следующем третьем примере мы по сути разбираем второй пример, который переделан на использование в цикле. То есть мы здесь будем неоднократно задавать пользователю вопрос, для того, чтобы как бы повторно выполнить несколько операций, несколько функций. Вначале сценария определяются те же функции, что и в предыдущем примере, но вот на 34 строке запускается цикл do..while, помните, что в цикле do..while у нас всегда выполняются первая итерация, а потом, в зависимости от условия мы либо продолжаем работать, либо повторяем итерацию цикла, либо выходим из цикла и продолжаем инструкции. Каждый раз, когда будет запускается цикл do..while, на каждой итерации мы будем запрашивать имя, фамилию, возраст. Отображать полученные данные, а потом на 38 строчке в переменную repeat записывать значения, которые пользователь выберет в диалоговом окошке с кнопками «Да» и «Нет». То есть мы спросим «Пройти заполнение еще раз?». Если пользователь нажмет на «Да», то в переменную repeat запишется значение true и мы на строке 38, условие у нас срабатывает, поэтому мы возвращаемся на начало и еще раз выполняем инструкцию. Если же пользователь выберет значение «Нет» - cancel нажмет, то repeat будет false, условие не срабатывает и наш сценарий выходит дальше, ну дальше нет инструкции, поэтому выполнение кода завершается. Давайте проверим. Вот «Введите свое имя, фамилию, возраст» и теперь смотрите, мы первый раз вывели, запустили первую-вторую функцию, ask и say. Теперь запускается функция confirm, которая спрашивает повторить или нет, если мы нажмем повторить, мы еще раз запускаем повторную функцию ask, она у нас спрашивает возраст и фамилию, потом нажимаем на Ок. Теперь, если мы нажмем на cancel, то у нас спрашивает повторно хотим ли мы заполнить эту анкету, если мы нажимаем на cancel, то цикл прекращается, повторно функцию мы уже не запускаем и прекращаем генерировать какой-то контент, в текущем документе. Вот получается, что использование функции, они даже упрощают понимание самого кода, нам не приходится вдавятся в детали, в подробности, мы можем просто запомнить, что делает каждая из этих функций и просто проанализировать алгоритм работы самого сценария. Вот у нас есть задание вопросов, потом что-то мы выводим пользователю, потом спрашиваем нужно ли повторить и выполняем повторение, если пользователь согласится с повтором. Но если бы у нас функции не было, то все, что находится внутри, детали реализации задания вопросов, детали реализации вывода результатов в документ, все эти детали находились в самом цикле do, и соответственно цикл был бы достаточно большим, достаточно сложно было бы его редактировать и контролировать, а так, когда у вас есть отдельные функции и у функции выражены четко обязанности функции, то вы может, если вы знаете, что нашли ошибку, в той части кода, в котором задают вопрос, то сразу понимаете куда нужно обратится, где нужно искать ошибку. Нужно открыть функцию ask и посмотреть, как она работает. Если вы зафиксировали ошибку в выводе пользователю данных, вы берете функцию say и проверяете, что в этой функции было написано неправильно. Если же у вас функции нету и все выполняется единым блоком кода, там несколько сотен строчек, то в таком случае вам нужно будет ковыряться вот в всем этом коде и искать где там что происходит. Поэтому функции, они очень часто помогаю сделать код более логическим, структурированным, сделать так, чтобы его потом проще сохранить. Если вам нужно пользоваться функциями, то сценарий становится упорядоченным и дальше с ним будет намного легче работать. В следующих примерах мы посмотрим, как можно задавать функциям аргументы. Как можно сделать функцию, которая при запуске будет получать от пользователя какие-либо данные. Как мы уже говорили, параметры функции определяются после имени функции, вот на 22 строке функция, как и в предыдущих наших примерах не принимает никаких параметров или аргументов. Аргументы и параметры – это одно и тоже самое. Вот на 20 строчке функция не принимает аргументов, а на строке 25 функция принимает 2 аргумента или 2 параметра. Первый параметр с именем х1, второй параметр с именем х2. Давайте пока разберем первую функцию, что она делает. В функции самм1 на строке 21 создается переменная result и в эту переменную записывается сумма двух других переменных, которые определены выше, на строке 15 и 16. Получается, что в переменную result будет записана сумма 25. И эту сумму на 22 строке мы отобразим в тело документа. На строке 26, когда мы разбираем эту функцию, мы не можем заранее знать какой результат будет отображается этой функцией, потому что при загрузке функции — вот эти переменные х1 и х2, в эти параметры могут быть заданы какие-либо значение. Какие именно мы сейчас не знаем, потому что выше таких переменных х1 и х2 у нас не объявлено. Получается, что кто-то запуская эту функцию передаст сюда значение. Например, в х1 передаст значение 1, в х2 значение – 4, например. Вот здесь на 26 строчке 1 + 4 даст результат 5. Этот результат будет записан в переменную result и в итоге отображен на 27 строке. Вот мы увидели 2 объявление функции. Давайте теперь разберем как эта функция запускается. Разницу вызова. На строке 33 мы берем sum1 и {} после sum2. Этот вызов правильный, потому что сама функция ничего не принимает, не требует никаких от пользователя значений. Под пользователем сейчас подразумевается разработчик, который запускает эту функцию. И вот сейчас на 33 строке у нас запускается функция и на экране мы выводим результат, результат 25. На строке 25 мы запускаем функцию sum2. И тоже не переедаем ей никаких параметров, это у нас не правильно потому что функция sum1 при определении требует два аргумента х1 и х2. Если мы не будем при вызове передавать никаких значений, то это будет означать, что х1 и х2 будут неопределенны. А мы уже с вами знаем, что когда будет, когда создаем переменную и не указываем значение для этой переменной. У переменной значением по умолчанию будет undefined. Давайте посмотрим, что получится если запустить такую функцию. Видите, первый раз мы увидели 25, когда вызвали sum1, а второй раз, когда мы вызвали саааамммммм2, мы результат увидели, как none. Потому что undefined + undefined получается непонятно что, not a number. Вот мы выводим этот результата. Вот когда на 36 строке мы запускаем функцию sum2, мы уже пользуемся ею корректно, мы передаем ей два значение, мы указываем, что первое значение будет значение переменной “c”. Переменная “c” у нас находится на 17 строке, в ней находится значение 20. Нас троке 36 у нас находится значение переменной “d”. Это значение придется как второй аргумент. В переменной “d” находится значение 21. Сейчас, на 36 строке, когда запускается эта функция, мы переходим на 25 строчку, здесь в х1 находится значение 20, в х2 находится значение 21. Соответственно сумма 21 и 20 дает результат 41, который мы выводим на экран. Видите, 41 отобразилось у нас в документе. При запуске функции необязательно передавать значения, которые взяты из переменных, мы можем прямо здесь установить значение 2 и 10, например. Вот сейчас, если мы запустим вот такую функцию, то результат, который выведется в документ, будет равен 12. Проверяем. Получилось 12. Давайте еще раз посмотрим, как это будет выглядеть в отладчике. Нажимаем F12, берем source, navigator, выбираем текущий документ, переходим к той части кода, которая нас интересует, вот нас интересует сейчас 36 строка. Ставим здесь breakpoint, нажимаем refresh, вот мы остановились на этой функции, остановили ее, давайте нажмем сейчас step_into, или F11, мы перепрыгнули функцию, если сейчас мы наведем мишкой на х1, Chrome подскажет, что в этой переменной значение 2, в х2 – значение 10. В соответствии с теми значениями, которые мы передавали при вызове. Эти значения попали в эти два параметра, или в эти два аргумента и теперь на 26 строке мы эти значения сложили, можем сейчас нажать stepinto или stepover, сейчас без разницы, потому что эта строчка не является вызовом функции. Давайте нажмем на F10, и переходим на следующею строку. Если наводим на result, видим, что Chrome подсказывает, что значение переменной 12. Значение мы дальше отображаем в тело документа. Его выведем сейчас. Вот 12 у нас отобразилось. Не забывайте пользоваться отладчиком, когда вы чего-то не понимаете, старайтесь с помощью отладчика выяснить что происходит внутри сценария.

В следующем пример мы посмотрим, как можно сделать так, чтобы функция требовала, чтобы одни параметры обязательно к ней были заданы, а другие параметры были опциональны. Вот сейчас на 15 строчке мы хотим сделать так, чтобы функция print принимала два аргумента. Первый аргумент- был обязательно, а второй аргумент, если его не предоставят, то функция возьмет свое какое-то значение по умолчанию. Задача функции print отображать в документе несколько сообщений, сообщений, которые были переданы первому аргументу. Вот если кто-то запускает эту функцию, первое, что делает функция – это 17 строчка. Проверят было ли предоставлено значение в параметр count. Если count равен undefined, то строка 18 мы говорим, что count будет равен значению три. То есть по умолчанию у нас всегда функция принт будет с count равен трем. Но если при запуске сюда передать значение, то на 17 строке условие не срабатывает и count будет равен тому значению, которое передал пользователь при вызове. Дальше после проверки на 21 строке мы запускаем цикл фор на количество итераций, равной значению переменной count. То есть count раз, на 22 строчке мы выводим сообщение переменной msg, то есть message. А в конце, когда все это заканчивается на 25 строке мы выводим horizontalRool. Вызов функции на 31 строчке, мы вызываем функцию только с один значение, со значением Hello, это значение первое, соответственно оно адресовано первому аргументу, переменной msg. НА 31 строке мы увидим, что сообщение Hello отобразится три раза, потому что count по умолчанию будет равен трем. На 32 строке, когда мы вызываем print двумя параметрами, двумя значениями world и семь. Это означает, что msg будет world, count будет равен семи. Соответственно условие не срабатывает и цикл срабатывает семь раз со значением, которое ввел пользователь. Hello три раза в соответствии со значением по умолчанию, world – семь раз. Вот этот пример показывает, как можно создать функцию и определить в функции опциональные параметры, которые не обязательны при запуске. Очень часто разработчики, которые создаю функцию с функциональными параметрами, добавляют вот такой комментарий, просто пишут необязательный параметр, или опциональный параметр для того, чтобы было понятно, что эта переменная, этот аргумент, он не обязательный при вызове. Все функции, которые мы сейчас с вами посмотрели, по сути они были процедурами, вот если вы работали с другими языками программирования, то вы сталкивались с таким термином как функция и процедура. Функция – это конструкция, блок кода, который мы запускаем, блок кода что-то делает, а потом возвращает нам результат. А процедура – это такой же блок кода, который мы запускаем, что-то происходит в этом блоке кода, но в результате ничего нам как клиентам этого блока кода, как запускающей стороне, нам никакой результат е возвращается. Вот мы с вами видели, что все наши примеры, в этих примерах функции не возвращали никаких данных в ответ. Мы их запустили, а в ответ ничего не получили. На самом деле в JavaScript нет такого понятия как процедуры, потому что любая функция всегда возвращает нам значение. Вот сейчас, у нас у всех примерах любая функция всегда возвращала значение undefined, просто мы им не пользовались и его игнорировали. Но запомните, что любая функция, если она не возвращает явно никаких данных, она вернет значение undefined. Давайте сейчас поострим как можно сделать функции, которые будут возвращать то что они рассчитали, то что они выполнили по окончанию своей работы.

Вот в следующем №6 примере мы посмотрим, как используется ключевое слово return и что оно делает. На строке 16 мы объявляем функцию sum, которая будет суммировать два входящих параметра «а» и «б». Но мы хотим сделать так, что функция, получив значение и посчитав сумму, не выводила сразу же результат в тело документа, а возвращала результат, которой получила. Мало ил как мы захотим с этим результатом работать, может мы не хотим его отображать в документе, может мы alert вывести, или мало что можно еще делать. Для того, чтобы функция просто вернула результаты своей работы, на 17 строке мы используем ключевое слово return, и после этого слова указываем то значение, которое функция должна будет вернуть после своей работы. Если запустить функцию sum, она у нас выполнит вычисления, отдаст результат своих исчислений, отдаст сумму двух входящих параметров. Вот когда мы пользуемся такими функциями, строка 20, нам необходимо использовать функции вот в таком ключе, таким синтаксисом. Мы создаем переменную, а потом эту переменную инициализируем результатом работы функции. Если мы запускаем любую функцию, которая есть в JavaScript коде, эта функция всегда что-то возвращает, и это возвращаемое значение мы можем присвоить переменной. Вот сейчас возвращаемое значение функции sum будет суммой двух аргументов, два и три. Поэтому в переменную рез запишется результат 5, результат на 22 строке мы отобразим. Давайте проверим. Вот отобразилось значение 5. Если мы сейчас возьмем и, например, поменяем 18 строчку, наберем ключевое слово return, функция у нас уже будет выполнять возврат значений. Теперь это значение будет undefined, потому что это значение по умолчанию. Если разработчик не указал, что функция возвращает, то функция всегда будет возвращать undefined. Давайте запустим. Видите, результат работы функции undefined. Поэтому если вы не написали return, или ключевое слово return просто не выполнилось в теле функции, это означает, что функция вернет значение undefined. И еще, то что вы должны понимать, ключевое слово return прекращает выполнение функции. Если после этого ключевого слова мы напишем сообщение, это сообщение у нас не выведется, потому что 17 строка, как только интерпретатор видит ключевое слово return и выполняет его, то вот на этом ключевом слове у нас и заканчивается работа функции. Мы из 17 строки перепрыгиваем в ту точку кода, где функция изначально запускалась, тот результат, который ключевым словом return был возвращен, мы записываем в переменную. Вот вернулась 5, а alert так и не отобразился.

Вот теперь небольшой такой пример с использованием нескольких функций, которые возвращают результат. Сейчас мы определили 4 функции, функция add, для сложения, функция sub, для получения разницы, mul – для умножения и div – для деления. В каждой функции мы выполняем арифметическую операцию и результат возвращаем с помощью ключевого слова return. После определения функций, на строке 32 от пользователя с помощью prompt мы получаем введите первое число, то есть первую цифру, операнд один, потом мы получаем знак операции, + - * / строка 34. Потом получаем операнд два, второе значение. И 35 строчка – создаем переменную, которая будет просто содержать в себе результат работы наших дальнейших вычислений. На 37-38 строке мы используя функцию parseInt, конвертируем значение, которое вводил пользователь в целочисленное, для того, чтобы все арифметические действия выполнялись как операции над числами, а не операции над строками. На 40 строчки создаем switch, для того, чтобы проверить какое значение было введено с помощью prompt на 33 строке. Если пользователь выбрал +, то 42 строчка в переменную result мы записываем значение, которое возвращает функция add, мы вызываем функцию, определенную выше, передаем в эту функцию два параметра, которые были получены от пользователя на 37-38 строке. И результат, который получится - записываем в переменную result, на 43 строчке у нас выполняется break, поэтому после этой строки мы выпрыгиваем за switch и отображаем надпись од 7 строки. Если у нас результат не undefined, потому что, мало ли мы не попали ни в один из case, если мы вот с брейка перепрыгнем сюда, то вот тогда мы отобразим, что вот такой операнд + символ + второй операнд = значение. Если мы сейчас выберем, например, нажмем не на +, вот здесь в переменную sun поместим не +, а допустим значение «*» - умножить, то тогда на 40 строчке, когда будет работать switch, мы перепрыгнем на строку 48, на 48 строчку, выполним этот блок кода. Выполнится уже другая функция, которая получит 2 параметра и получит произведение 2 значений, это значение здесь запишется в result и здесь запишется. Давайте проверим как будет работать этот код. Введите первое число. Вводим два. Введите знак арифметической операции – вводим «+» и второе число – тоже два. Вот результат «2+2=4». Вводим 5*12, получается – 60. Вот такой простенький калькулятор написанный на JavaScript.

В следующем примере мы разберем пример с использованием нескольких аргументов. Если копнуть немножко глубже, то на самом деле функция в языке JavaScript – это не просто как бы синтаксическая единица, это тип данных. Если вы работали с языками там С++, Pascal, C#, любыми языками программирования, в большинстве языков функция это именно вот синтаксическая конструкция, это часть языка, с помощью которой мы определяем блок кода для повторного использования. А вот в JavaScript – функция – это тип данных и любая функция – это на самом деле – объект. Вот сейчас пока вы можете рассматривать функции как код для повторения, но если вы будут дальше работать с JavaScript кодом, если вы будут прослушивать следующий курс JavaScript углубленный, то вы там будете очень часто сталкивается вот с тем, что функция – это объект, а не просто кусочек кода. И вот сейчас мы тоже с вами увидим вот эту особенность функции в JavaScript коде, увидим, что функции, как объекты содержат в себе какие-то свойства. То есть функция кроме кода, который нужно выполнить, также в себе содержит разные значение, которые могут помочь создавать сложные и интересные сценарии. Сейчас у нас на 16 строке есть функции max, задача этой функции показать нам максимально значение того аргумента, который был передан при вызове. Вот если мы запустим функцию max и передадим в «а» значение 1, в «и» значение 10, а в «с» значение – 100, то функция вернет то значение, которое максимальное. Значение параметра «с», потому что там была записана сотня. Но также мы хоти сделать так, чтобы функция принимала у нас не только три параметра, а допустим 5, 10, 20, то есть неограниченное количество параметров. И в JavaScript это сделать очень легко, мы можем сделать так, чтобы функция принимала хоть 50 параметров, нам в принципе все равно. На 18 строке, когда эту функцию запустят, мы создадим переменную maxValue, вот в этой переменной будет находится максимальное значение, которое мы найдем в параметрах. Но изначально максимальным значением мы считаем минимальное значение, которое вообще может быть записано в целочисленную переменную. Мы записываем минус бесконечность. И потом посредством цикла, посредством проверок, мы это значение будем менять. На строке 19 вот мы изначально выводим какое значение записано в переменную maxValue, изначально мы записали NegativInfinity, то есть минус бесконечность. После вывода этого сообщение, на строке 21 запускается цикл и обратите внимание, на какое количество итераций. Мы берем переменную arguments и берем ее свойства length. Откуда взялась переменная arguments, если посмотреть вот в текущем коде, нигде такую переменную мы с вами не определяли. Вот как раз эта переменная, она у нас доступна сейчас в данном блоке кода, потому что функция – это не просто кусочек кода, это не синтаксическая единица языка JavaScript – это объект. Вот когда мы, вот сейчас выделенный код, который вы видите у себя, это есть код, который находится внутри объекта с именем макс внутри функции. И вот у объектов функции есть несколько свойств. Одно из свойств – это свойство arguments, которое в себе содержит все аргументы передаваемые функции при запуске. Вот сейчас, если мы запусти эту функцию вот таким вот способом, на строке 28 видите мы передаем 1, 2, 3, 4, 5. Пять значений. И вот получается сейчас, когда эта функция начинает работать, в переменной «а», «b», «с» находится -33, 33, 777. А вот остальные значения, они у нас не представлены параметрами, но они все равно доступны в функции, они как бы доступны функции через массив arguments. Массив arguments – это все значение, которые пришли в функцию при вызове. Вот сейчас в этом массиве, кроме первых трех значений, которые доступны так же через параметры, находится еще и два дополнительных значения, -666 и -22. Вот сейчас мы запускаем цикл на 21 строке, и на каждой итерации проверяем. Если arguments, вот как раз предыдущий урок, мы смотрели массивы, если и-тый элемент массива, на первой итерации – это -33. Если он больше, чем maxValue, а 33 будет больше чем минус бесконечность в любом случае, то есть если больше, то тогда 23 строчка, максимальное значение – оно у нас будет равно текущему аргументу – из массива arguments. То есть в maxValue мы записываем -33. Потом следующая итерация, мы берем следующий элемент из массива arguments 33, 33 больше чем maxValue? maxValue сейчас у нас -33, соответственно положительное 33 больше чем -33. maxValue теперь у нас новое значение, значение 33. Следующая итерация, здесь у нас 777, здесь 33. 777 больше чем 33, поэтому maxValue теперь у нас 777. Следующая итерация, здесь у нас находится -666, а maxValue у нас три семерки. Три семерки больше, условие не срабатывает, в условие мы не попадаем и maxValue не изменяем. То есть в итоге в переменной maxValue останется максимальное значение, которое при запуске было передано в параметры. Вот это максимально значение, которое по завершению этого цикла мы получим, это значение на 25 строке мы вернем с помощью ключевого слова return. И на 28 строчке видит, в переменную rez мы записываем тот результат, который был возвращен в функцию. Ну на 33 строке мы этот результат показываем в документ. В нашем случае, максимально значение сейчас будет 777. Вот это значение у нас вывелось. Если мы добавим еще несколько параметров, вот сейчас максимальное значение будет у нас 1000, это максимальное значение на 30 строке отобразится. Вот отобразилась 1000. В этом примере, что показывает этот пример, то что вам нужно запомнить, создавая функцию, вы можете сделать так, чтобы функция принимала неограниченное количество параметров, и вы в функции могли получать доступ ко всем этим параметров. Для этого вам необходимо пользоваться свойством arguments, которое доступно в теле функции. За пределами функции, это свойство у вас будет недоступным. Но когда вы работаете в этой функции, посредством этого свойства вы можете получать доступ ко всем параметрам, которые были переданы в функцию при запуске.

И последний, девятый пример из первой директории, показывает, как мы можем сделать функцию, которая будет проверять правильное ли количество параметров передали функции при запуске. Иногда нам важно, чтобы запускаемая функция принимала столько аргументов, сколько было указано при определении функции. Вот в предыдущем примере мы специально сделали так, чтобы функция принимала неограниченное количество параметров. Но сейчас мы хотим сделать именно так, чтобы в функции у нас принималось ровно три параметра, ни меньше, ни больше. Если количество параметров не совпадает с требованными, то наша функция вообще никаких операций не будет производить. Определяем функцию мы на 16 строке. Видите, что функция принимает скорей всего три координаты: х, у, z. На 19 строчке у нас идет проверка. Если arguments.lenght не равно 3, то выводим сообщение о ошибке. И больше по сути ничего не делаем, ведь этот блок кода у нас не срабатывает. Если же arguments равно 3, то условие на 19 строке не сработает, сработает блок else, увидим сообщение, что у нас корректно были получены данные и строка 25, запустив цикл for, все значения, который были получены в параметрах мы отобразим на экран через запятую. Вот посмотрите теперь на то как мы функцией пользуемся. На 30 строке мы запускаем функцию с именем f, то есть вот эту функцию и передаем 4 значения при запуске. Четыре значение - это перебор, наша функцию требует три значения, это условие на 19 строке срабатывает и выводит ошибку. А вот на строке 31, когда мы передаем три значения, функцию получив эти три значения не запускает if, попадает в блок else и соответственно срабатывает у нас как бы сама логика функции. Ну и 32 строчка, тоже функцию не срабатывает, так как количество параметров у нас меньше трех. Первый раз – ошибка. Четыре аргумента было получено, второй раз все нормально, вывелись все элементы, третий раз опять ошибка – у нас меньше аргументов чем надо, было получено два аргумента. Вот в первой части урока мы рассмотрели с вами как создаются функции, как сделать так, чтобы функция возвращала результат своей работы, как сделать так, чтобы функция принимала входные параметры и как можно сделать функцию, которая работает с неограниченным количеством параметров, для этого в функции есть свойство arguments. Эти примеры обязательно хорошо рассмотрите, изучите, потому что это основа работы с функциями.

Вторая часть урока будет посвящена областям видимости. Перед тем, как перейти к областям видимости мы повторим с вами что происходит с переменными, которые не создавали. Нам пригодится дальше для того, чтобы понимать следующий пример. На 13 строке мы создаем переменную «а». Помните, что если переменной мы не присваиваем значение, то значение этой переменной при чтении будет у нас undefined. Для остальных переменных мы задаем конкретное значение и соответственно переменные у нас инициализируются и получают какой-то определений тип данных. Переменная «b» со значением 777 она у нас будет number. На строке 15 переменная «c» использует значение переменной «b», соответственно это тоже будет number и тоже со значением 777. Переменная «d» будет типа null и содержать в себе единственное возможное для типа null значение null. Создав эти переменные мы отображаем их значения на экран и выводим все те значение, которые тут мы определили. Если же мы попытаемся получить доступ к переменной, которую не создавали, вот как на строке 24, то эта строчка кода становится ошибкой. На этой строчке интерпретатор прекращает интерпретировать все, что мы определили в сценарии и код находящийся ниже просто прекращает работать. Поэтому 24 строчка и все строчки кода, которые мы могли бы написать ниже, они не перестанут работать. Давайте проверим. Вот первая переменная undefined, потом обе переменные «b» и «c» со значением 777, переменная «d» – null. Последняя переменная – она у нас отсутствует. Если мы чтобы проверить, что действительно весь код перестает работать, если мы этот код поставим в начало, интерпретатор первое дело, что сделает – это выполнит эту строку, получит здесь ошибку и не сможет выполнять код идущий далее. Давайте запустим. Видите, в таком случае у нас вообще ничего не отображается. Поэтому следите за использованием переменных, не используйте переменные если вы их не определяли. То есть если мы хотя бы создали переменную, как только мы ее с помощью ключевого слова var определили, эта переменная остается, тип этой переменной undefined, значение этой переменной undefined. Дальше мы эту переменную можем спокойно использовать. А вот если вы пытаетесь читать переменные, которых нету, вот к чему это приводит. Приводит к ошибке.

Теперь давайте посмотрим, что такое область видимости. В следующем примере мы разберем с вами понятие глобальной и локальной области видимости. В языке JavaScript есть только две области видимости. Глобальная – это область видимости, где работают все наши сценарии. И локальная область видимости. Это область видимости, отдельной функции. Если вы работали в языке C# или С++ у вас есть глобальная область видимости и локальная область видимости, которая определяется функцией, которая определяется условием, циклом. В языке JavaScript таких вложенных областей видимости просто не существует. Либо у нас глобальная область видимости, либо область видимости функции. Если мы собираемся создать переменную глобальную, которая будет доступна абсолютно всем сценариям текущего приложения, текущего документа, нам нужно просто создать переменную в теге <script>. Если мы создаем var global, эта переменная становится глобальной, потому что она не находится внутри функции. Если мы определяем функцию и создаем переменную с ключевым словом var внутри функции, то эта переменная будет доступна только в теле этой функции. Получается глобальная область видимости, вот она, вот то что мы нарисуем сейчас красным цветом – это и есть глобальная область видимости. А локальная область видимости это вот эта вот часть, только то, что находится в функции. Глобальная область видимости, если мы создаем переменную, вот здесь, global, если мы ниже создадим еще один тег скрипт, то тег скрипт будет представлять глобальную область видимости и в новом скрипте переменная global тоже будет существовать. То есть глобальные переменные – они общие. Они доступны даже тем JavaScript сценариям, которые разрабатывали другие разработчики. Если этот JavaScript сценарий подключить к вашей странице, то чужой JavaScript код может видеть ваши глобальные переменные. То есть почему они глобальные? Потому что доступны абсолютно всем. А вот локальные переменные, они доступны только в той области, в которой мы их создавали. Область видимости создается вот фигурными скобками, операторными скобками, все, что между этими скобками находится – это одна область видимости. Эта область видимости можем использовать свои локальные переменные и так же эта область видимости так как она находится внутри глобальной области видимости, эта область видимости может получать доступ также и к глобальным переменным. Вот сейчас мы на 20 строке увидим, что переменная global у нас доступна в функции F. Мы увидим здесь текс глобальная переменная. И также мы увидим, что доступна локальная переменная, на 21 строке мы увидим текст локальная переменная. Функцию мы определили, на строке 26 функцию мы эту запускаем, то она начинает у нас работать, создает локальную переменную, выводит все эти сообщения. После запрещения функции мы отображаем значение глобальной переменной. Мы увидим, что и здесь переменная была доступна и здесь переменная доступна у нас, видно текст глобальная переменная, но вот на 31 строчке отображение к локальной переменной уже ни к чему не приводит. Локальная переменная здесь неопределенна, локальна переменная доступна только в этой области видимости, то есть вот этой локальной области видимости. Поэтому на строке №31 мы не имеем права обращаться к переменной local, ее просто здесь не существует. Если бы переменную local отсюда подняли выше и поставили ее после глобальной, тогда переменная local, она по сути имела глобальную область видимости. А в этом случае, вот в таком варианте использования как на 31 строке, это у нас обращение по сути к несуществующей переменной. Давайте запустим и проверим. Глобальная и локальная переменная. То, что выводится функцией, видите, цвет navy, вот у нас отобразились данные, а потом, когда мы попытались вывести значения global и local за функции, то первая строчка отобразилась, а вторая строчка стала причиною ошибки, потому что переменная неопределенна. Переменную мы не смогли запустить.

В следующем примере показано, что произойдет если в глобальной области видимости находится переменная, которая называется точно так же, как и переменная заложена в локальную область видимости. На 15 строке создается глобальная переменная с именем global, на строке 18 еще одна переменная с именем local, но эта переменная глобальная, потому что вы видите, она определена в теге <script>, не внутри функции, а вот в скрипте. В самой функции F на строке 23 создается еще одна переменная с именем local. Имена этих переменных совпадают, но пока будет работать функция F, значение этой переменной временно будет перекрывать значение глобальной переменной, поэтому на строке 26, когда мы обращаемся к переменной с именем local, мы обращаемся к данной переменной, а когда мы закончим работу в этой функций, когда мы обратимся к переменной local на 34 строчке, то по сути мы будем работать с переменной, которая находится на 18 строке, будем выводить это значение. Получается, что внутри функции мы можем перекрывать значение глобальных переменных, если создадим локальную переменную с тем же именем, что и у глобальной. Вот видите глобальна переменная локальная переменная, а потом после выхода за функцию вот у нас есть глобальная и еще одна глобальная переменная. То есть на строке 34 мы на самом деле обращаемся к значению, которое устанавливалось на строке 18. А на строке 26 мы обращаемся к значению, которое устанавливалось на 23 строке. Вот это такая вот особенность работы с локальными и глобальными функциями.

В №4 примере показана ошибка, которую очень часто могут допускать разработчики. Всегда создавая переменную используйте ключевое слово var. Потому что если вы не установите ключевое слово var, это может привесит к следующему поведению. Вот на строке 19 мы определяем функцию. На 22 строчки создаем переменную с именем global, но не используя ключевое слово var. Если мы не устанавливаем ключевое слово var, это означает, что мы создаем глобальную переменную. Получается, что здесь эта переменная доступна как внутри этой функции, так как она глобальная, так и за пределами этой функции. На строке 35 мы имеем доступ к переменной global. Вот когда эта функция запускается – переменная global создается, а потом, когда на 35 строке мы к этой переменной обращаемся, мы видим ее результат – глобальная переменная, точнее ее значение. Видите, глобальная переменная вот вывелась на строке 24 и вторая строчка это вывелось на строке 35. Давайте проверим что произойдет если мы раскомментируем 30 строку, раскомментируем и запустим. Видите, браузер не отобразил никаких сообщений. Почему так произошло? Функцию на 19 строке мы определили, но код, который там находится еще не срабатывал. Далее на 30 строке мы обращаемся document.write, выводим в тело документа сообщение, и это значение, которое мы собираемся отобразить, это переменная global. Переменная global не была определена, переменная global создается только тогда, когда выполняется код заложенный в функции. А вы помните, чтобы код, находящийся в функции, запустился, выполнился, функцию необходимо запустить. Запускаем мы функцию на 32 строчке, то есть вот здесь, после того, как выведем значение глобальная переменная. Поэтому на строке 30 из-за отсутствия переменной у нас происходит ошибка, интерпретатор не в состоянии выполнять код, соответственно не выполняются ни это, ни следующие строчки кода, которые здесь заложены. Поэтому здесь у нас все прекращает работу. Если мы функцию перенесем на строку, например, 17, если мы ее вызовем раньше, то в таком случае у нас создается переменная, мы сможем с этой переменной работать на 30 и на 35 строке. Либо другой вариант, мы можем просто розкоментировать 16 строку и создать глобальную переменную на 16 строчке, вывести ее на 30 строке, а потом, когда мы запустим функцию, на строке 22 мы просто переопределим значение глобальной переменной, перепишем это значение, которое было создано здесь. Из-за того, что код, который мы создаем з глобальными переменными внутри функции получается такой вот неоднозначный и запутанный. Старайтесь всегда создавая переменную функции использовать ключевое слово var, потому что таким образом вы четко говорите, что данная переменная – локальная, она работает только в этой функции. Соответственно никаких проблем с понимаем к какой переменной вы сейчас обратитесь к локальной или глобальной никаких проблем не возникает. Возьмите себе за правило. Создавая переменную всегда используйте ключевое слово var.

Теперь следующий пример. Локальных областей видимости у нас может быть несколько, то есть каждая функция выступает своей собственной локальной областью видимости и из одной локальной области переменная не может быть получена в другой локальной области. Вот в примере, который мы сейчас открыли, у нас есть две функции, функция «а» и функция «b», эти функции мы на 38-39 строке вызываем. В функции «а» у нас создается локальная переменная с именем «а» и ее значение отображается на экран. В функции «b» локальная переменная «b», и тоже значение выводится на экран. Сейчас у нас есть по сути три области видимости в этом примере. Есть первая область видимости – глобальная, вот эта вот область видимости, вторая область видимости – это вот эта локальная функция «а» и область видимости локальная для функции «b». Между этими областями видимости мы не можем иметь никакого взаимодействия, то есть если расскоментировать эту строчку, в переменную «b» в локальной области видимости функции «а» мы не получим. То есть здесь мы можем работать только с теми переменными, которые были созданы в области видимости функции «а». И тоже самое касается с областью видимости функции «b», тут мы можем работать только с теми переменными, которые были созданы здесь, в этой области видимости. Ну а глобальная область видимости она и на то глобальная, то есть то что было создано в глобальной области видимости будет доступно и для функции «b» и для функции «а». Если мы так код запустим – он срабатывает, обе переменные выводится и если мы рассоментируем обращение к переменной «b», которое не существует в переменной «а», в функции «а», у нас выведется вот 21 строчка код сработает, а потом выводится исключение для интерпретатора и на 25 строке интерпретатор перестанет работать и перестанет выполнять все инструкции, которые заложены в нашем коде.

Следующий пример еще объясняет дополнительно работу области видимости. Я думаю, что многие из вас, кто работал с каким-нибудь другим языком программирования, увидев этот пример подумает, что язык JavaScript очень странный и непонятный язык. Мы работая с другими языками программирования привыкли, что если мы создаем условия, если мы создаем цикл, какую-то конструкцию, если в этом допустим цикле мы создаем переменную, то переменная доступна только для цикла. За пределами цикла переменная использоваться уже не будет. Но из-за того, то в JavaScript есть только две области видимости – глобальная и локальная – область видимости при создании цикла она у нас не появляется просто, вот из-за этого она у нас есть такие достаточно интересные поведение в коде. Когда на 14 строке создается цикл, мы указываем, что в цикле есть счетчик, изначальное значение его ноль, цикл будет работать до тех пор, пока счетчик меньше трех и на каждой итерации будет просто увеличивать счетчик. Вот все, что делает цикл. В большинстве языков программирования счетчик, который мы создали в цикле будет доступен только вот в этой части кода. То есть вот в той области видимости, в которой была создана вот данными фигурными скобками. На самом деле, когда на 14 строке мы создаем вот эту переменную, мы создаем ее по сути, как глобальную переменную, потому что мы не находимся сейчас в функции. Переменная counter становится глобальной, она доступна как к этому циклу, так и всем другим сценариям, которые есть в этом приложении. Поэтому на 19 строке, когда мы еще раз выводим сообщение, обращаемся к counter, у нас все корректно срабатывает. Переменная counter доступна даже после того, как цикл завершил свою работу. Видите, 0,1,2 это то, что выводилось в счетчике, в цикле точнее, а настройке 19 вот желтым цветом вывелся блок с счетчиком, и мы видим счетчик у нас продолжает работать, мы имеем доступ. Для тех, кто перешел в JavaScript с другого языка программирования, это достаточно такое странное поведение. Но я думаю, что вы привыкнете к такому использованию областей видимости.

И №7 пример также показывает особенности работы областей видимости в функциях, локальных областей видимости. По сути, код, который мы сейчас видим, это по сути тот же код, который и в №6 примере, но мы создали функцию в которую поместили цикл и вывод значение счетчика. И сейчас мы видим, что на строке 16 мы создали счетчик, мы так же проверили счетчик, использовали его для создания цикла, но когда мы закончили цикл, на 21 строке счетчик все-равно для нас доступен. Если в предыдущем примере мы создали счетчик как глобальную переменную, то сейчас мы создали счетчик как локальную переменную и получается, что все так же виден вот в этой области видимости. Если мы его создали где-нибудь в функции, он доступен во все этой функции. В других языках программирования вот эти фигурные скобочки, они бы тоже считались бы областью видимости, у нас бы еще появилась область видимости для цикла for, но это не пройдет в JavaScript коде, в JavaScript коде область видимости только одна, область видимости функции, поэтому создав переменную, эта переменная будет доступна в любой части функции. И кстати очень такой важный пример, который мы не показываем в этих примерах, но вы можете столкнутся с таким кодом, вы можете написать его и не понимать, почему у вас код работает неправильно. Если вы создаете переменную, вот, например, var «а» вот здесь, в конце, допустим создаете и устанавливаете для этой переменной значение 1. Переменную «а» вы можете начать использовать в самом начале. alert «а». Она будет работать, потому что интерпретатор в JavaScript коде работает по следующему принципу. Когда интерпретатор видит, что у вас есть функция, первое, что делает интерпретатор – это проходится по всей функции, собирает все переменные, которые тут находятся. То есть еще до того, как запустится код в функции, интерпретатор будет знать, что у вас есть переменная counter и переменная «а». Когда интерпретатор соберет информацию об этих переменных, он изначально создаст их, переменные будут со значением undefined. И вот зная о переменных, интерпретатор начнет выполнять уже код. На строке 15 первое, что сделает этот интерпретатор выполнит alert и выведет значение переменной «а». Но так как переменная «а» у нас будет инициализирована только на 22 строке, а интерпретатор уже знает о ее существовании, то сейчас на 15 строке мы увидим значение undefined. А вот здесь, после инициализации, мы уже увидим значение 1. Видите undefined, выполнится цикл и значение 1. Поэтому будьте осторожны при объявлении переменных. Очень часто JavaScript разработчики всегда эти переменные определять вначале функции. Вот есть даже такой шаблон. Вы пишете ключевое слово var, потом определяете первую переменную, потом вторую переменную, допустим, третью переменную, определяете все переменные вначале, а потом уже используете их в оставшееся части функции. Вот можете для себя пользоваться таким же правилом. Объявили переменные, возможно присвоили этим переменным стартовые значения, а потом уже начинайте этими переменными пользоваться. Это будет хороший способ обезопасить себя от этих ошибок, которые мы увидели с вами при определении переменной ближе к концу функции. На этом мы завершаем вторую часть урока, которая посвящена областям видимости.

Третья часть урока, которая посвящена областям видимости. Тереть часть урока – дополнительные варианты использование функции. Начнем мы с вами третью часть с такого понятия как рекурсия или рекурсивный вызов. Рекурсия или самовызов – это запуск функции из самой же функции. Вот на 13 строке определяется функция с именем F. Эта функция принимает параметр counter. На 15 строке counter уменьшается на 1, потом выводится сообщение какое-то значение counter вот сейчас в этой функции. На строке 19 делается проверка. Если counter не равен нулю, то в таком случае мы еще раз запуская функцию F, передавая counter, который был уменьшен. То есть со строки 20 мы прыгаем на строку 13 и повторно запускаем этот же код, уменьшаем counter, выводим сообщение и делаем проверку – если counter еще не равен нулю, повторно запускаем сами себя. То есть вот это и есть сама рекурсия, рекурсивный вызов, когда функция запускает сама себя. Первая часть запуска функции будет выводить вот это сообщение, но когда у нас на 19 строке условие у нас не сработает, и мы не попадем в строку 20, не сможем запустить сами себя, то тогда все функции, которые мы запускали, они начнут выводить вот это сообщение, значение счетчика, которое было после запуска. Сейчас мы попробуем это графически отобразить, чтобы вы понимали, как это все работает. Видите, вначале срабатывала первая часть функции, вот 17 строчка – счетчик был 2, 1, 0. А потом вторая часть функции, на 22 строчке вывела счетчика 0, 1, 2. Более подробно рекурсивный вызов рассматривается на курсе C# Starter, так как это основы программирования, но мы сейчас с вами тоже потратим немножко времени для того, чтобы понять как именно работает этот код, почему у нас так странно отображаются сообщения, почему вначале выводится 2, 1, 0, потом 0, 1, 2. Давайте сейчас представим, что функция, которую мы сейчас запускаем вот это наша функция, вот то что сейчас нарисую это есть функция F. В первой части функции мы счетчик уменьшаем, ведь изначально, когда на 25 строке мы запускаем функцию, мы передаем в счетчик значение три. Вот получается, что если сюда в counter попало значение три, то на 15 строчке счетчик уменьшается до двойки и это значение мы отображаем. На строчке 19, вот в этой вот функции мы делаем проверку counter не равен нулю. Так как counter сейчас равен 2, то на 20 строке мы запускаем сами себя же. То есть вот здесь у нас идет условие и в этом условии мы запускаем свою же функцию. Запускаем еще одну функцию, передаем в эту функцию счетчик, который вот здесь равен 2, в этой функции счетчик уже будет равен 1, потому что на 15 строке мы его уменьшим, счетчик равен 1, мы этот счетчик выводим, а потом на 19 строке делаем проверку, счетчик не ноль – да, о не ноль, вот здесь значение 1, поэтому вот здесь в условии, в этой копии функции мы условие проходим, попадаем в само условие и еще раз вызываем сами себя, вызываем еще такую же функцию, передавая в эту функцию счетчик со значение 1. То есть в этой локальной области видимости у функции в счетчике будет значение ноль, потому что на строке 15 эта функция счетчик уменьшает. Раз у этой функции значение ноль, мы это значение выведем, на 19 строке условие уже не срабатывает, то есть мы не можем вызвать функцию еще раз, потому что счетчик равен нулю, мы это условие проходим и на 20 строке выводим сообщение уже другим цветом, желтым цветом выводим значение счетчика ноль. Но как вы видели в предыдущих примерах, когда мы функцию запустили, мы перешли в тело функции, выполнили тело функции и вернулись обратно в ту часть кода, где мы функцию запускали. Вот вы видите, мы функцию выполнили, теперь нам нужно перейти обратно и завершить те предыдущие функции которые у нас остались. Как только вот здесь мы до конца выполняем вот эту функцию, мы возвращаемся вот туда, в точку вызова, где в предыдущую функцию и выводим желтым цветом значение счетчика, которое было в этой функции, то есть вот 22 строку, которая выполняется для этой копии функции. Выводим значение 1, уже желтым цветом. Когда эта функции до конца выполняется, она возвращается в ту часть кода, где была вызвана, возвращается в эту функцию, и эта функция соответственно тоже выводит желтым цветом значение 2, значение своего счетчика. Вот и получается, что у нас при рекурсивном вызове в нас вначале вывелось 2, потом 1, потом 0. Потом эта функция не сможет рекурсивно запустить саму себя еще раз, поэтому вывела нолик, который во второй части функции, вернулась в предыдущую функцию – вывела 1, в предыдущей функции вывела 2. Поэтому у нас получилось 2, 1, 0 и 0, 1, 2. Вот так работает рекурсивный вызов. Для чего может использоваться рекурсивный вызов?

В примере №2 мы посмотрим, как можно с помощью саморекурсии посчитать факториал. На строке 7 мы попросим пользователя ввести значение, на строке 8 конвертируем это значение в целочисленное, потом у нас идет функция, сейчас мы разберем, что она делает, а на 18 строке мы выводим факториал вот этого числа, знак восклицания, вы знаете как записывается факториал цифрой и знак восклицания, а потом результат, который возвращает функция, факториал с параметром input. То есть факториал – это произведение нескольких чисел. Если мы скажем 4! – это означает, что нам нужно 1*2*3*4 и вот этот результат, результат умножения, это и будет факториалом. Как мы можем делать вот так, чтобы сюда мы передаем значение 4, а в результат получаем 1*2*3*4, то есть произведение вот всех этих натуральных чисел. Мы можем создать функцию факториал, которая будет саморекурсивно работать. Когда мы запускаем функцию, первое что она проверяет – значение переменной «х», то есть параметра, который сюда попал. Если параметр меньше или равен 1, то мы возвращаем 1. Но если это условие не срабатывает, на строке 15 мы берем «х» и умножаем «х» на вызов этой же функции, факториал, но с уменьшенным значением «х» *1. Поэтому, когда мы сюда передаем значение 4, мы умножаем 4 на результат умножения 4-1, в свою очередь, в той функции, которую мы запустим будет результат умножения 3-1, а во вложенной функции 2-1. То есть в итоге у нас получится, что из-за этого рекурсивного вызова мы получим каждый раз факториал возвращает 1, потом результат умножения 2 на 1, потом результат умножения 3*1 и результат умножения 4 на все предыдущие результаты. И в итоге вот это рекурсивный вызов даст нам факториал указанного числа. Давайте попробуем. Введем число 4, Факториал 4 – 24. Введем значение 20, факториал числа будет вот таким большим значением.

Следующая интересная возможность, которая встречается в JavaScript – это создания функций-литералов. Так как функция – это тип данных, мы можем спокойно создать переменную и в эту переменную присвоить функцию. На 13 строке создается переменная с именем F. И в эту переменную, вместо обычного значение, которое мы привыкли присваивать, записывается функция. Вот это и есть функция-литерал, потому что мы создали по сути значение, которым инициализируем переменную. Тип переменной F – function. Если вы вспомните самый первый наш урок, на слайде мы разбирали, что один из типов данных – это функция. Вот мы видим, что действительно можем создать переменную типа функция. Вот мы сейчас это видим на 13 строке. Функция, которую мы присваиваем переменной, мы не устанавливаем этой функции имя, то есть по сути эта функция – это анонимная функция безымянная функция, мы ее не можем запустить просто так, само по себе, потому что мы не знаем, как она называется. Но когда эта функция находится в переменной F. По сути имя функции это есть имя переменной и на строке 17, когда мы обращаемся к переменной F, так как в переменной находится функция, чтобы эту функцию запустить, нам нужно установить круглые скобки после переменной. Вот у нас по сути запуск функции, не важно, как она была определена, либо как отдельное объявление функции, либо функциональный литерал, запуск функции всегда выглядит одинаково. Вот мы запустили функцию, которая выведет сообщение Hello. На строке 20 мы переменную “f” взяли и переприсвоили ей значение, записали в переменную новую функцию. Старую функцию, которая хранится в переменной мы выбросили, а новая функция теперь выводит сообщение bye. Проверяем на 24 строке, вызываем функцию, видим, что здесь уже выводится сообщение bye. Вот Hello, а второй раз bye. В этом примере мы увидели, как использовать функции bye. В следующих курсах мы будем очень часто принимать эти функции, когда мы создаем обработчики на события, мы тоже будем изучать такую тему, очень часто мы используем функции литералы. Так же в JavaScript коде можно сделать, чтобы функция в себе содержала вложенную функцию. Это не является ошибкой, это даже приветствуется. На строке 13 определяется функция с именем author. На строке 15 мы вызываем функцию inner. Мы видим, что функция inner она у нас определена вот, на строке 17. Вот фигурные скобки, которыми определяется тело функции author, мы видим, что между этими скобками находится еще одно определение вложенной функции с именем inner. Эта функция выводит параграф с текста – inner-function. И вот мы эту inner function вызвали на 15 строке и ее же вызвали на 21 строке, но для того, чтобы этот код заработал, на строке 24 мы запускаем функцию author. Когда мы вызываем на 24 строке author функцию, у нас начинает выполняться 15 строка и 21 строка. И по сути функция inner, она доступна только для локального кода, для функции author. За пределами функции author к этой функции мы обращаться не будем. Поэтому это один из принципов инкапсуляции. Если вы сталкивались с этим термином, то в JavaScript мы можем прятать какую-то функциональность с помощью вот таких вложенных функций.

В следующем примере показан пример использования таких вложенных функций. На строке №13 у нас есть функция, которая будет считать гипотенузу. В эту функцию мы передаем два параметра «а» и «b», и на 15 строке внутри функции гипотенуза у нас есть функция pow, то есть power, возведение в квадрат. Эта функция принимает один параметр и возвращает как бы этот параметр умноженный сам на себя. Просто «х» в квадрате. На строке 19 мы используем библиотеку Math, точнее не библиотеку, а объект Math. С этим объектом мы еще не сталкивались, но рекомендую его посмотреть, посмотреть его содержимое, его методы. Видите, что в этом объекте есть различные функции для получение синуса, косинуса, различных констант, например, число пи и так далее. Вот мы сейчас на объекте масс вызываем функцию sqrt. sqrt– это квадратный корень. Вот мы вызываем квадратный корень, а в квадратный корень, точнее в параметр, передаем значение квадрат «a», и квадрат «b». Вот мы вызываем локально эту функцию, которая доступна только нам, получаем квадрат «a», квадрат «b», и возвращаем результат в виде квадратного корня. Этот квадратный корень мы выводим на 22 строке. Вот мы вывели результат.

И в последнем примере мы разберем то как можно еще использовать функции. Так как функция – это тип данных, то мы без проблем можем передать функцию в качестве аргумента другой функции. Посмотрите сейчас на текущий пример. На строке 14 создается переменная с именем add и в эту переменную записывается функция, принимающая два параметра. На 18 строке – переменная sub, функция, которая тоже принимает два параметра, но эта функция у нас выполняет вычитание, а на 15 строчке – сложение. На 24 строке у нас есть функция show, которая принимает три аргумента. Первый аргумент имеет имя CallBack Function. Если вы встречаете такую фразу как CallBack, вот вообще термин CallBack, это функция обратного вызова. Это означает, что сюда, в функцию show, когда мы ее вызываем мы в эту функцию в качестве параметра должны передать еще одну функцию, CallBack функцию. И эта CallBack функция в какой-то определенный момент времени будет запущена. То есть функция show сама решит, когда нужно запустить CallBack Function. Запустит этот CallBack Function и по сути на оповестит. Можете воспринимать CallBack Function как допустим вы запускаете функцию show, и передаете функции show свой номер телефона, чтобы функция show, когда она что-то там надумает, смогла позвонить и оповестить о каких-то изменениях. CallBack Function – это функция, которую нужно запустить для того, чтобы оповестить наш код о каких-то изменениях. Можете воспринимать для простоты вот так эту функцию. Значит мы запускаем show, передаем три параметра – CallBack, «а» и «b». И смотрите, что мы делаем на 26 строке. Мы подразумеваем, что CallBack Function она умеет выполоть какие-то действия над двумя переменными. Выполнять какие-то действия, получить результат и потом с этим результатом что-то делать. Вводить его каким-то красивым способом на страницу, отправлять куда-то на сервер, то есть делать какие-то с ним операции. Вот получается, что на 26 строке мы запускаем CallBack Function, которая первым параметром была передана, в эту функцию передаем значение, которые были получены здесь в качестве аргументов «a» и «b». То, что функция возвращает мы записываем в переменную result, а потом что-то с этой переменной делаем. Выводим в документ или еще какие-то операции делаем. То есть задача функции show, получать на вход функцию, которая будет производить вычисления, получать на вход параметры, над какими нужно производить вычисления, запустить функцию, передать в эту функцию параметры, получить результат и что-то сделать с результатом. И вот строка 32, мы просим функция show, покажи то что произойдет, если взять функцию add, взять значение 10 и 20. То есть функции show мы сейчас передаем add метод, вот эту функцию, бросаем функцию show, бросаем в функцию show значение 10, значение 20. И в результате видим, что у нас сумма двух этих значений отображается в параметре. Строка 34, просим, чтобы функция show взяла функцию sub, провела вычитания, 50-30 и результат вывела в документ. Вот таким способом мы отображаем результат. Суть этого примера показать, что вы можете спокойно делать функции аргументами других функций. Вы можете функцию передать в качестве аргумента. А другая функция может воспользоваться переданной функцией, что-то с ней здесь, вызвать ее, посмотреть на результат, выполнить любые операции. В будущем вы еще не раз столкнетесь с CallBack функциями, особенно если будете работать с различными библиотеками, например, с JQuery библиотекой, moottolls, вы будете постоянно передавать CallBack функции в чужой код, чтобы чужой код вам выдавал оповещение, чтобы чужой код вызывая вашу CallBack функцию оповещал вас о каких-то изменениях. Но с этим мы еще с вами поговорим отдельно.

На этом мы заканчиваем №4 урок, посвященный функциям, в этом уроке мы рассмотрели, как определяются функции, мы разобрали с вами различные области видимости, которые существуют в JavaScript коде, узнали, что есть глобальная и локальная область видимости и посмотрели несколько примеров, которые показали нам что такое саморекурсия, что такое функция, литералы и мы увидели, что функция – это тип данных и соответственно функцию мы можем передавать в качестве параметра в друге функции. На этом урок, посвященный функциям мы заканчиваем. Спасибо за внимание. До новых встреч.

© 2017 ITVDN, все права защищены