Для чего нужны функции
Перейти к содержимому

Для чего нужны функции

  • автор:

Функция (программирование)

Функция от англ. function — фрагмент программного кода, к которому можно обратиться из другого места программы [1] .

Обращение к функции происходит по её имени (адрес первой инструкции, входящей в функцию). После выполнения функции управление возвращается обратно в адрес возврата, где данная функция была вызвана.

Функция может принимать параметры (аргументы) и должна возвращать некоторое значение. Частным случаем функции является процедура, которая ничего не возвращает. Она может быть объявлена или определена.

Объявление функции, включает в себя имя функции, список параметров (аргументов), тип возвращаемого значения.

Определение функции включает в себя имя функции, список параметров (аргументов), тип возвращаемого значения и тело функции.

Для того, чтобы использовать ранее определённую функцию, необходимо в требуемом месте программного кода указать имя функции и перечислить передаваемые в функцию параметры (аргументы).

Функция имеет локальную область видимости, поэтому все объявления внутри неё не будут влиять на глобальную область видимости. Исключение составляет использование заранее определённых глобальных переменных или объектов.

Параметры (аргументы) функции могут передаваться по ссылке или по значению. В случае передачи параметра (аргумента) по ссылке, функция будет работать с непосредственным объектом. И наоборот, в случае передачи параметра по значению, функция будет работать с копией объекта.

Виды функций

1) вложенные функции. Вложенной функцией называют функцию определённой в теле другой функции;

2) лямбда функции. Лямбда функцией называют функцию определённой в месте использования и не имеющей идентификатора (имени);

3) абстрактные (виртуальные) функции. Виртуальной функцией называют функцию, определённой в классе для последующей перегрузки в дочерних классах;

4) методы. Методом называют функцию, объявленной или определённой в классе;

5) рекурсивная функция. Рекурсивной называют функцию вызывающей саму себя [2] .

Функции Python — это объекты первого класса

Функции Python — это объекты первого класса. Их можно присваивать переменным, хранить в структурах данных, передавать в качестве аргументов другим функциям и даже возвращать в качестве значений из других функций.

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

В этом руководстве я приведу ряд примеров, которые помогут развить это интуитивное понимание. Каждый последующий пример будет опираться на предыдущий, поэтому вам, возможно, захочется читать их последовательно и даже опробовать некоторые из них в сессии интерпретатора Python по ходу дела.

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

В этом руководстве я буду использовать в демонстрационных целях функцию yell . Это простой пример с легко узнаваемым результатом:

def yell(text): return text.upper() + '!' >>> yell('hello') 'HELLO!'

Функции — это объекты

Все данные в программе Python представлены объектами или отношениями между объектами. Строки, списки, модули и функции — все это объекты. В Python нет ничего особенного в функциях.

Поскольку функция yell является объектом в Python, вы можете присвоить ее другой переменной, как и любой другой объект:

>>> bark = yell

Эта строка не вызывает функцию. Она берет объект функции, на который ссылается yell , и создает второе имя, указывающее на него, bark . Теперь можно выполнить тот же базовый объект функции, вызвав bark :

>>> bark('woof') 'WOOF!'

Объекты функций и их имена — это две разные вещи. Вот еще одно доказательство: исходное имя функции ( yell ) можно удалить. Поскольку другое имя ( bark ) все еще указывает на базовую функцию, вы все еще можете вызвать функцию через него:

>>> del yell >>> yell('hello?') NameError: "name 'yell' is not defined" >>> bark('hey') 'HEY!'

Кстати, Python для целей отладки во время создания прикрепляет строковый идентификатор к каждой функции. Доступ к этому внутреннему идентификатору можно получить с помощью атрибута name :

>>> bark.__name__ 'yell'

Хотя функции name по-прежнему «yell», это не влияет на то, как можно получить к ней доступ из кода. Этот идентификатор — всего лишь средство отладки. Переменная, указывающая на функцию, и сама функция — это две разные вещи.

Начиная с Python 3.3 существует также qualname , который служит аналогичной цели и предоставляет строку квалифицированного имени для разграничения имен функций и классов.

Функции можно хранить в структурах данных

Функции можно хранить в структурах данных, как и другие объекты. Например, можно добавить функции в список:

>>> funcs = [bark, str.lower, str.capitalize] >>> funcs [, , ]

Доступ к объектам функций, хранящихся внутри списка, осуществляется так же, как и к любому другому типу объектов:

>>> for f in funcs: . print(f, f('hey there')) 'HEY THERE!' 'hey there' 'Hey there'

Можно даже вызвать объект функции, хранящийся в списке, не присваивая его сначала переменной. Можно выполнить поиск и затем сразу же вызвать полученный «свободный» объект функции в рамках одного выражения:

>>> funcs[0]('heyho') 'HEYHO!'

Функции можно передавать другим функциям

Поскольку функции являются объектами, их можно передавать в качестве аргументов другим функциям. Вот функция greet , которая форматирует строку greeting, используя переданный ей объект функции, а затем выводит ее:

def greet(func): greeting = func('Hi, I am a Python program') print(greeting)

Приветствие, которое получается в результате, можно изменить, передавая различные функции. Вот что произойдет, если передать в greet функцию yell :

>>> greet(yell) 'HI, I AM A PYTHON PROGRAM!'

Чтобы сгенерировать другой вид приветствия, можно определить новую функцию, Например, функция whisper может работать лучше, если вы не хотите, чтобы программы на Python звучали так, словно их автор Оптимус Прайм:

def whisper(text): return text.lower() + '. ' >>> greet(whisper) 'hi, i am a python program. '

Мощной является возможность передавать объекты функций в качестве аргументов другим функциям. Она позволяет абстрагироваться от поведения и передавать его в программах. В этом примере функция greet остается неизменной, но на ее вывод можно влиять, передавая различные варианты приветствия.

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

Классическим примером функций высшего порядка в Python является встроенная функция map . Она принимает функцию и итерируемый объект и вызывает функцию на каждом элементе в итерируемом объекте, выдавая результаты по мере выполнения.

Вот как можно отформатировать последовательность всех приветствий сразу, с помощью маппинга функции yell :

>>> list(map(yell, ['hello', 'hey', 'hi'])) ['HELLO!', 'HEY!', 'HI!']

map просмотрел весь список и применил функцию yell к каждому элементу.

Функции могут быть вложенными

Python позволяет определять функции внутри других функций. Их часто называют вложенными или внутренними функциями. Вот пример:

def speak(text): def whisper(t): return t.lower() + '. ' return whisper(text) >>> speak('Hello, World') 'hello, world. '

Итак, что же здесь происходит? Каждый раз, когда вы вызываете speak , он определяет новую внутреннюю функцию whisper и затем вызывает ее.

И вот в чем загвоздка — whisper не существует вне speak :

>>> whisper('Yo') NameError: "name 'whisper' is not defined" >>> speak.whisper AttributeError: "'function' object has no attribute 'whisper'"

Но что, если вы действительно хотите получить доступ к вложенной функции whisper из внешней функции speak ? Ну, функции являются объектами — можно вернуть внутреннюю функцию вызывающей родительской функции.

Например, вот функция, определяющая две внутренние функции. В зависимости от аргумента, переданного функции верхнего уровня, она выбирает и возвращает вызывающему одну из внутренних функций:

def get_speak_func(volume): def whisper(text): return text.lower() + '. ' def yell(text): return text.upper() + '!' if volume > 0.5: return yell else: return whisper

Обратите внимание, что get_speak_func фактически не вызывает ни одну из своих внутренних функций — она просто выбирает соответствующую функцию на основе аргумента volume , а затем возвращает объект функции:

>>> get_speak_func(0.3) .whisper at 0x10ae18> >>> get_speak_func(0.7) .yell at 0x1008c8>

Конечно, можно продолжить и вызвать возвращенную функцию либо напрямую, либо присвоив ее имя переменной:

>>> speak_func = get_speak_func(0.7) >>> speak_func('Hello') 'HELLO!'

Подумайте об этом немного. Это означает, что функции могут не только принимать поведение через аргументы, но и возвращать его. Круто же?

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

Функции могут захватывать локальное состояние

Вы только что увидели, что функции могут содержать внутренние функции и что можно даже возвращать эти (иначе скрытые) внутренние функции из родительской функции.

А теперь пристегнитесь, потому что дальше будет еще безумнее — мы собираемся погрузиться в еще более глубокую область функционального программирования. (У вас ведь был перерыв на кофе, верно?)

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

Чтобы проиллюстрировать эту мысль, я немного перепишу предыдущий пример get_speak_func . Чтобы сделать возвращаемую функцию сразу вызываемой, новая версия сразу принимает аргументы «громкость» и «текст»:

def get_speak_func(text, volume): def whisper(): return text.lower() + '. ' def yell(): return text.upper() + '!' if volume > 0.5: return yell else: return whisper >>> get_speak_func('Hello, World', 0.7)() 'HELLO, WORLD!'

Посмотрите внимательно на внутренние функции whisper и yell . Заметили, что у них больше нет параметра text ? Но каким-то образом они все еще могут обращаться к параметру text , определенному в родительской функции. На самом деле, они, похоже, захватывают и «запоминают» значение этого аргумента.

Функции, которые делают это, называются лексическими замыканиями (или просто замыканиями, для краткости). Замыкание запоминает значения из своей лексической области видимости, даже когда поток программы больше не находится в этой области.

На практике это означает, что функции могут не только возвращать поведение, но и настраивать это поведение. Вот еще один пример, иллюстрирующий эту идею:

def make_adder(n): def add(x): return x + n return add >>> plus_3 = make_adder(3) >>> plus_5 = make_adder(5) >>> plus_3(4) 7 >>> plus_5(4) 9

В этом примере make_adder служит фабрикой для создания и настройки функций «adder». Обратите внимание, что функции «adder» по-прежнему могут обращаться к аргументу n функции make_adder (вложенная область видимости).

Объекты могут вести себя как функции

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

Если объект является вызываемым, для него можно использовать круглые скобки () и передавать ему аргументы вызова функции. Вот пример вызываемого объекта:

class Adder: def __init__(self, n): self.n = n def __call__(self, x): return self.n + x >>> plus_3 = Adder(3) >>> plus_3(4) 7

За кулисами «вызов» экземпляра объекта как функции пытается выполнить метод call объекта.

Конечно, не все объекты могут быть вызываемыми. Поэтому существует встроенная функция callable для проверки того, является ли объект вызываемым или нет:

>>> callable(plus_3) True >>> callable(yell) True >>> callable(False) False

Основные выводы

  • В Python все является объектом, включая функции. Их можно присваивать переменным, хранить в структурах данных, передавать или возвращать другим функциям (первоклассным функциям).
  • Функции первого класса позволяют абстрагироваться и передавать поведение в программах.
  • Функции могут быть вложенными, они могут захватывать и переносить с собой часть состояния родительской функции. Функции, которые делают это, называются замыканиями.
  • Объекты можно сделать вызываемыми, что позволяет во многих случаях обращаться с ними как с функциями.

Как работать с файлами в Python? Поговорим об этом на открытом уроке, в ходе которого научимся с помощью Python читать и записывать данные в текстовые файлы различных форматов: JSON, CSV, XML. Обсудим особенности работы с каждым из этих форматов и изучим подходящие библиотеки. Вспомним, что такое контекстные менеджеры и поговорим, почему их нужно использовать для работы с файлами.

  • python
  • python qa
  • работа с файлами
  • Функции Python
  • объекты первого класса
  • Блог компании OTUS
  • Python

Функция

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

В разговорной речи функцией называют какую-то возможность программного обеспечения, например функция записи звука. Но в программировании значение несколько иное: это часть программного кода со своими особенностями.

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

«IT-специалист с нуля» наш лучший курс для старта в IT

IT-специалист с нуля

Наш лучший курс для старта в IT. За 2 месяца вы пробуете себя в девяти разных профессиях: мобильной и веб-разработке, тестировании, аналитике и даже Data Science — выберите подходящую и сразу освойте ее.

картинка - 2023-03-14T191232.869

Профессия / 8 месяцев
IT-специалист с нуля

Попробуйте 9 профессий за 2 месяца и выберите подходящую вам

vsrat_7 1 (2)

Для чего нужны функции

В программировании часто приходится выполнять одни и те же действия: перебирать массив, создавать набор объектов или получать данные с сервера. Если каждый раз писать команды для этих действий с нуля, программа получится большой, громоздкой и нечитаемой.

Именно в таких ситуациях нужны функции — «программы» в программе. Они позволяют один раз описать, как выполнять какое-то действие, а потом сколько угодно раз запускать это действие одной строчкой кода. Это можно сделать практически в любой момент выполнения, а еще функцию можно вызывать с разными аргументами — и получать разный результат.

Благодаря функциям код становится более чистым, лаконичным и понятным:

  • действия разделены по функциям, а не хаотично повторяются в разных местах кода;
  • программу легче отлаживать, ведь разработчик сам знает, где «лежит» какое действие;
  • код можно использовать повторно и не писать одно и то же снова и снова;
  • функции облегчают работу с элементами интерфейса: при нажатии на кнопку можно просто вызывать функцию с нужным действием, а не писать код отдельно.

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

Что можно делать с функциями

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

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

Вызывать. Когда программист задает функцию, она не выполняется сразу — это просто описание. Чтобы функция сработала, ее нужно вызвать: написать в нужном участке кода команду вызова. Команда обычно состоит из названия функции и двух скобок. Например, так: myFunction().

Вызывать с аргументами. Иногда, чтобы функция сработала как надо, ей нужно передать какие-то данные. Причем при разных вызовах эти данные могут различаться. В таком случае можно создать функцию с параметрами:

  • при создании функции описать, что она будет получать на входе — какие-то переменные с любым удобным разработчику именем;
  • при вызове указывать в круглых скобках значения аргументов, фактических значений, которые будут передаваться в функцию. Это могут быть числа, строки, объекты и так далее.

Например, функция multiply умножает заданное число на 2. Чтобы она могла каждый раз получать новое число, при создании функции указывают параметр number: function multiply(number). Это значит, что на вход функция будет получать какой-то number и иметь возможность с ним работать. А при вызове вместо number будут писать в скобках нужное число или переменную. Например, так: multiply(2) или multiply(myMoney). 2 и myMoney — аргументы, которые передаются в параметр.

Получать значения. Функция может возвращать в основную программу какой-то результат, и с ним можно работать: записывать в переменную или использовать в вычислениях. Обычно для возврата используют ключевое слово return, а после него пишут то, что нужно вернуть. Существуют и функции, которые ничего не возвращают, — иногда бывает нужно и такое.

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

Курс для новичков «IT-специалист
с нуля» – разберемся, какая профессия вам подходит, и поможем вам ее освоить

Как работают функции

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

  • Чаще всего при передаче параметра в функцию отправляется копия значения. Это значит, что если внутри функции изменить переданное значение, то во внешнем коде оно останется прежним.
  • В некоторых языках программирования разработчик сам может выбрать, что передать в функцию: копию значения или изначальную переменную. Во втором случае, если поменять переданную переменную в функции, она изменится и во внешнем коде.

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

Как задают функции

Способы объявить функцию различаются в зависимости от языка программирования. Всего существует несколько основных видов описания:

  • декларативное — стандартный вариант, существующий практически во всех языках. Функцию описывают отдельно от других действий, описание начинают со слова function или другого в зависимости от языка. Такая функция не исполняется сразу, а существует как отдельный блок кода и «ждет», пока ее вызовут;
  • через выражение — вариант, который распространен в языке JavaScript. Функцию создают прямо внутри какого-то выражения, например a = function… и так далее. Такая функция выполнится сразу после появления, в рамках этого же выражения;
  • стрелочное — функцию описывают без ключевого слова function, вместо него используют стрелку =>. У такого описания свой синтаксис, и обычно его применяют для простых функций в одну-две строчки.

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

Что такое чистая функция

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

Например, если функция просто каждый раз складывает 2+2, ее можно назвать чистой. Правда, практической ценности у такой функции обычно минимум.

На практике часто получается так, что функция взаимодействует с переменными и значениями из внешнего кода. А значит, может их менять. Когда такое происходит, возникают побочные эффекты: разработчик не всегда может отследить, что и где поменяла функция. То есть код становится менее предсказуемым, и его сложнее отлаживать.

Поэтому чистые функции считаются правилом хорошего тона. Чтобы их писать, нужно соблюдать несколько правил:

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

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

  • Например, если функция возвращает текущее время или генерирует случайное число, она не сможет постоянно выдавать один и тот же результат — то есть не сможет быть чистой.
  • А если функция записывает что-то в файл или читает из него информацию, она общается со внешним окружением — и тоже не является чистой.

Но считается, что, если у разработчика есть возможность написать для какого-то действия чистую функцию — лучше писать чистую. Это упрощает код и облегчает работу с ним в будущем.

Разница между функцией, методом и процедурой

Есть еще два понятия, которые связаны с функциями, — метод и процедура. Это похожие на функции конструкции, но у них есть свои особенности.

Метод. Так называют функцию внутри объекта. Объект — структура данных, которая описывает какую-то сущность: кнопку, предмет в компьютерной игре, запись из базы данных и так далее. У объекта есть свойства и методы.

  • Свойства — это переменные, которые описывают объект. Например, вес персонажа, цвет предмета и так далее.
  • Методы — это действия, которые объект может выполнять. Скажем, объект «кот» может выполнять действия «бегать», «прыгать», «спать», «есть», «вылизываться» и так далее.

Фактически, методы — это тоже функции. Но они не самостоятельны. Методы привязаны к объекту и выполняются в связке с ним. Даже вызывать их обычно можно, только если обратиться к имени объекта.

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

Как начать работать с функциями

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

Статьи по теме:

Функции

Зачастую нам надо повторять одно и то же действие во многих частях программы.

Например, необходимо красиво вывести сообщение при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.

Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.

Примеры встроенных функций вы уже видели – это alert(message) , prompt(message, default) и confirm(question) . Но можно создавать и свои.

Объявление функции

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

Пример объявления функции:

function showMessage()

Вначале идёт ключевое слово function , после него имя функции, затем список параметров в круглых скобках через запятую (в вышеприведённом примере он пустой) и, наконец, код функции, также называемый «телом функции», внутри фигурных скобок.

function имя(параметры)

Наша новая функция может быть вызвана по своему имени: showMessage() .

function showMessage() < alert( 'Всем привет!' ); >showMessage(); showMessage();

Вызов showMessage() выполняет код функции. Здесь мы увидим сообщение дважды.

Этот пример явно демонстрирует одно из главных предназначений функций: избавление от дублирования кода.

Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.

Локальные переменные

Переменные, объявленные внутри функции, видны только внутри этой функции.

function showMessage() < let message = "Привет, я JavaScript!"; // локальная переменная alert( message ); >showMessage(); // Привет, я JavaScript! alert( message ); // 

Внешние переменные

У функции есть доступ к внешним переменным, например:

let userName = 'Вася'; function showMessage() < let message = 'Привет, ' + userName; alert(message); >showMessage(); // Привет, Вася

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

let userName = 'Вася'; function showMessage() < userName = "Петя"; // (1) изменяем значение внешней переменной let message = 'Привет, ' + userName; alert(message); >alert( userName ); // Вася перед вызовом функции showMessage(); alert( userName ); // Петя, значение внешней переменной было изменено функцией

Внешняя переменная используется, только если внутри функции нет такой локальной.

Если одноимённая переменная объявляется внутри функции, тогда она перекрывает внешнюю. Например, в коде ниже функция использует локальную переменную userName . Внешняя будет проигнорирована:

let userName = 'Вася'; function showMessage() < let userName = "Петя"; // объявляем локальную переменную let message = 'Привет, ' + userName; // Петя alert(message); >// функция создаст и будет использовать свою собственную локальную переменную userName showMessage(); alert( userName ); // Вася, не изменилась, функция не трогала внешнюю переменную

Глобальные переменные

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

Глобальные переменные видимы для любой функции (если только их не перекрывают одноимённые локальные переменные).

Желательно сводить использование глобальных переменных к минимуму. В современном коде обычно мало или совсем нет глобальных переменных. Хотя они иногда полезны для хранения важнейших «общепроектовых» данных.

Параметры

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

В нижеприведённом примере функции передаются два параметра: from и text .

function showMessage(from, text) < // параметры: from, text alert(from + ': ' + text); >showMessage('Аня', 'Привет!'); // Аня: Привет! (*) showMessage('Аня', "Как дела?"); // Аня: Как дела? (**)

Когда функция вызывается в строках (*) и (**) , переданные значения копируются в локальные переменные from и text . Затем они используются в теле функции.

Вот ещё один пример: у нас есть переменная from , и мы передаём её функции. Обратите внимание: функция изменяет значение from , но это изменение не видно снаружи. Функция всегда получает только копию значения:

function showMessage(from, text) < from = '*' + from + '*'; // немного украсим "from" alert( from + ': ' + text ); >let from = "Аня"; showMessage(from, "Привет"); // *Аня*: Привет // значение "from" осталось прежним, функция изменила значение локальной переменной alert( from ); // Аня

Значение, передаваемое в качестве параметра функции, также называется аргументом.

  • Параметр – это переменная, указанная в круглых скобках в объявлении функции.
  • Аргумент – это значение, которое передаётся функции при её вызове.

Мы объявляем функции со списком параметров, затем вызываем их, передавая аргументы.

Рассматривая приведённый выше пример, мы могли бы сказать: "функция showMessage объявляется с двумя параметрами, затем вызывается с двумя аргументами: from и "Привет" ".

Значения по умолчанию

Если при вызове функции аргумент не был указан, то его значением становится undefined .

Например, вышеупомянутая функция showMessage(from, text) может быть вызвана с одним аргументом:

showMessage("Аня");

Это не приведёт к ошибке. Такой вызов выведет "*Аня*: undefined" . В вызове не указан параметр text , поэтому предполагается, что text === undefined .

Если мы хотим задать параметру text значение по умолчанию, мы должны указать его после = :

function showMessage(from, text = "текст не добавлен") < alert( from + ": " + text ); >showMessage("Аня"); // Аня: текст не добавлен

Теперь, если параметр text не указан, его значением будет "текст не добавлен"

В данном случае "текст не добавлен" это строка, но на её месте могло бы быть и более сложное выражение, которое бы вычислялось и присваивалось при отсутствии параметра. Например:

function showMessage(from, text = anotherFunction()) < // anotherFunction() выполнится только если не передан text // результатом будет значение text >

Вычисление параметров по умолчанию

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

В приведённом выше примере, функция anotherFunction() не будет вызвана вообще, если указан аргумент text .

С другой стороны, функция будет независимо вызываться каждый раз, когда аргумент text отсутствует.

Использование параметров по умолчанию в ранних версиях JavaScript

Ранние версии JavaScript не поддерживали параметры по умолчанию. Поэтому существуют альтернативные способы, которые могут встречаться в старых скриптах.

Например, явная проверка на undefined :

function showMessage(from, text) < if (text === undefined) < text = 'текст не добавлен'; >alert( from + ": " + text ); >

…Или с помощью оператора || :

function showMessage(from, text) < // Если значение text ложно, тогда присвоить параметру text значение по умолчанию // заметим, что при этом пустая строка text === "" будет также считаться отсутствующим значением text = text || 'текст не добавлен'; . >

Альтернативные параметры по умолчанию

Иногда имеет смысл присваивать значения по умолчанию для параметров не в объявлении функции, а на более позднем этапе.

Во время выполнения функции мы можем проверить, передан ли параметр, сравнив его с undefined :

function showMessage(text) < // . if (text === undefined) < // если параметр отсутствует text = 'пустое сообщение'; >alert(text); > showMessage(); // пустое сообщение

…Или мы можем использовать оператор || :

function showMessage(text) < // если значение text ложно или равняется undefined, тогда присвоить text значение 'пусто' text = text || 'пусто'; . >

Современные движки JavaScript поддерживают оператор нулевого слияния ?? . Его использование будет лучшей практикой, в случае, если большинство ложных значений, таких как 0 , следует расценивать как «нормальные».

function showCount(count) < // если count равен undefined или null, показать "неизвестно" alert(count ?? "неизвестно"); >showCount(0); // 0 showCount(null); // неизвестно showCount(); // неизвестно

Возврат значения

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

Простейшим примером может служить функция сложения двух чисел:

function sum(a, b) < return a + b; >let result = sum(1, 2); alert( result ); // 3

Директива return может находиться в любом месте тела функции. Как только выполнение доходит до этого места, функция останавливается, и значение возвращается в вызвавший её код (присваивается переменной result выше).

Вызовов return может быть несколько, например:

function checkAge(age) < if (age >= 18) < return true; >else < return confirm('А родители разрешили?'); >> let age = prompt('Сколько вам лет?', 18); if ( checkAge(age) ) < alert( 'Доступ получен' ); >else

Возможно использовать return и без значения. Это приведёт к немедленному выходу из функции.

function showMovie(age) < if ( !checkAge(age) ) < return; >alert( "Вам показывается кино" ); // (*) // . >

В коде выше, если checkAge(age) вернёт false , showMovie не выполнит alert .

Результат функции с пустым return или без него – undefined

Если функция не возвращает значения, это всё равно, как если бы она возвращала undefined :

function doNothing() < /* пусто */ >alert( doNothing() === undefined ); // true

Пустой return аналогичен return undefined :

function doNothing() < return; >alert( doNothing() === undefined ); // true

Никогда не добавляйте перевод строки между return и его значением

Для длинного выражения в return может быть заманчиво разместить его на нескольких отдельных строках, например так:

return (some + long + expression + or + whatever * f(a) + f(b))

Код не выполнится, потому что интерпретатор JavaScript подставит точку с запятой после return . Для него это будет выглядеть так:

return; (some + long + expression + or + whatever * f(a) + f(b))

Таким образом, это фактически стало пустым return .

Если мы хотим, чтобы возвращаемое выражение занимало несколько строк, нужно начать его на той же строке, что и return . Или, хотя бы, поставить там открывающую скобку, вот так:

return ( some + long + expression + or + whatever * f(a) + f(b) )

И тогда всё сработает, как задумано.

Выбор имени функции

Функция – это действие. Поэтому имя функции обычно является глаголом. Оно должно быть кратким, точным и описывать действие функции, чтобы программист, который будет читать код, получил верное представление о том, что делает функция.

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

Например, функции, начинающиеся с "show" обычно что-то показывают.

Функции, начинающиеся с…

  • "get…" – возвращают значение,
  • "calc…" – что-то вычисляют,
  • "create…" – что-то создают,
  • "check…" – что-то проверяют и возвращают логическое значение, и т.д.

Примеры таких имён:

showMessage(..) // показывает сообщение getAge(..) // возвращает возраст (получая его каким-то образом) calcSum(..) // вычисляет сумму и возвращает результат createForm(..) // создаёт форму (и обычно возвращает её) checkPermission(..) // проверяет доступ, возвращая true/false

Благодаря префиксам, при первом взгляде на имя функции становится понятным, что делает её код, и какое значение она может возвращать.

Одна функция – одно действие

Функция должна делать только то, что явно подразумевается её названием. И это должно быть одним действием.

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

Несколько примеров, которые нарушают это правило:

  • getAge – будет плохим выбором, если функция будет выводить alert с возрастом (должна только возвращать его).
  • createForm – будет плохим выбором, если функция будет изменять документ, добавляя форму в него (должна только создавать форму и возвращать её).
  • checkPermission – будет плохим выбором, если функция будет отображать сообщение с текстом доступ разрешён/запрещён (должна только выполнять проверку и возвращать её результат).

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

Сверхкороткие имена функций

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

Например, фреймворк jQuery определяет функцию с помощью $ . В библиотеке Lodash основная функция представлена именем _ .

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

Функции == Комментарии

Функции должны быть короткими и делать только что-то одно. Если это что-то большое, имеет смысл разбить функцию на несколько меньших. Иногда следовать этому правилу непросто, но это определённо хорошее правило.

Небольшие функции не только облегчают тестирование и отладку – само существование таких функций выполняет роль хороших комментариев!

Например, сравним ниже две функции showPrimes(n) . Каждая из них выводит простое число до n .

Первый вариант использует метку nextPrime :

function showPrimes(n) < nextPrime: for (let i = 2; i < n; i++) < for (let j = 2; j < i; j++) < if (i % j == 0) continue nextPrime; >alert( i ); // простое > >

Второй вариант использует дополнительную функцию isPrime(n) для проверки на простое:

function showPrimes(n) < for (let i = 2; i < n; i++) < if (!isPrime(i)) continue; alert(i); // простое >> function isPrime(n) < for (let i = 2; i < n; i++) < if ( n % i == 0) return false; >return true; >

Второй вариант легче для понимания, не правда ли? Вместо куска кода мы видим название действия ( isPrime ). Иногда разработчики называют такой код самодокументируемым.

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

Итого

Объявление функции имеет вид:

function имя(параметры, через, запятую) < /* тело, код функции */ >
  • Передаваемые значения копируются в параметры функции и становятся локальными переменными.
  • Функции имеют доступ к внешним переменным. Но это работает только изнутри наружу. Код вне функции не имеет доступа к её локальным переменным.
  • Функция может возвращать значение. Если этого не происходит, тогда результат равен undefined .

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

Функция, которая получает параметры, работает с ними и затем возвращает результат, гораздо понятнее функции, вызываемой без параметров, но изменяющей внешние переменные, что чревато побочными эффектами.

  • Имя функции должно понятно и чётко отражать, что она делает. Увидев её вызов в коде, вы должны тут же понимать, что она делает, и что возвращает.
  • Функция – это действие, поэтому её имя обычно является глаголом.
  • Есть много общепринятых префиксов, таких как: create… , show… , get… , check… и т.д. Пользуйтесь ими как подсказками, поясняющими, что делает функция.

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

Задачи

Обязателен ли "else"?

важность: 4

Следующая функция возвращает true , если параметр age больше 18 .

В ином случае она запрашивает подтверждение через confirm и возвращает его результат:

function checkAge(age) < if (age >18) < return true; >else < // . return confirm('Родители разрешили?'); >>

Будет ли эта функция работать как-то иначе, если убрать else ?

function checkAge(age) < if (age >18) < return true; >// . return confirm('Родители разрешили?'); >

Есть ли хоть одно отличие в поведении этого варианта?

Оба варианта функций работают одинаково, отличий нет.

Перепишите функцию, используя оператор '?' или '||'

важность: 4

Следующая функция возвращает true , если параметр age больше 18 .

В ином случае она задаёт вопрос confirm и возвращает его результат.

function checkAge(age) < if (age >18) < return true; >else < return confirm('Родители разрешили?'); >>

Перепишите функцию, чтобы она делала то же самое, но без if , в одну строку.

Сделайте два варианта функции checkAge :

  1. Используя оператор ?
  2. Используя оператор ||
function checkAge(age) < return (age >18) ? true : confirm('Родители разрешили?'); >

Используя оператор || (самый короткий вариант):

function checkAge(age) < return (age >18) || confirm('Родители разрешили?'); >

Обратите внимание, что круглые скобки вокруг age > 18 не обязательны. Они здесь для лучшей читаемости кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *