Javascript arguments

Всем доброго времени суток. На связи Алексей Гулынин. В прошлой статье вы узнали про область видимости переменных в Javascript. В данной статье я бы хотел поговорить про объект arguments в Javascript. Все аргументы функции являются локальными переменными. Давайте создадим функцию, которая будет возвращать сумму двух чисел:
В данном примере переменные "a" и "b" являются локальными переменными функции "sum".
Возникает вопрос: а что делать, если мы хотим возвращать сумму произвольного числа переменных? Не указывать же весь список параметров в определении функции. Для этого у каждой функции есть локальная переменная – объект arguments , который предоставляет доступ ко всем аргументам переданным функции.
Давайте переделаем наш пример:
У объекта arguments есть 2 свойства:
- length — количество переданных аргументов
- callee — ссылка на саму функцию
С помощью свойства arguments.callee.length есть возможность узнать количество аргументов, которое функция ожидает получить (количество переменных, использованных при определении функции в качестве аргументов). Если, например, у нас есть функция, ожидающая передачи строго трех аргументов, а ей при вызове передается два, то произойдет ошибка. Чтобы избежать ее, можно перед исполнением кода сравнить эти значения. Давайте напишем такой пример:
В качестве домашнего задания: напишите функцию, которая возвращает произведение чисел.
В данной небольшой статье вы узнали про объект arguments в Javascript и о том, как с ним работать.
На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.
Функции

— это блок программного кода на языке JavaScript, который определяется один раз и может выполняться, или вызываться, многократно. Возможно, вы уже знакомы с понятием «функция» под другим названием, таким как подпрограмма, или процедура. Функции могут иметь параметры: определение функции может включать список идентификаторов, которые называются параметрами и играют роль локальных переменных в теле функции.
При вызове функций им могут передаваться значения, или аргументы, соответствующие их параметрам. Функции часто используют свои аргументы для вычисления возвращаемого значения, которое является значением выражения вызова функции. В дополнение к аргументам при вызове любой функции ей передается еще одно значение, определяющее контекст вызова — значение в ключевом слове this.
Функции в языке JavaScript являются объектами и могут использоваться разными способами. Например, функции могут присваиваться переменным и передаваться другим функциям. Поскольку функции являются объектами, имеется возможность присваивать значения их свойствам и даже вызывать их методы.
В JavaScript допускается создавать определения функций, вложенные в другие функции, и такие функции будут иметь доступ ко всем переменным, присутствующим в области видимости определения.
Определение функций
Определение функции начинается с ключевого слова function, за которым указываются следующие компоненты:
Идентификатор, определяющий имя функции
Имя является обязательной частью инструкции объявления функции: оно будет использовано для создания новой переменной, которой будет присвоен объект новой функции. В выражениях определения функций имя может отсутствовать: при его наличии имя будет ссылаться на объект функции только в теле самой функции.
Пара круглых скобок вокруг списка из нуля или более идентификаторов, разделенных запятыми
Эти идентификаторы будут определять имена параметров функции и в теле функции могут использоваться как локальные переменные.
Пара фигурных скобок с нулем или более инструкций JavaScript внутри
Эти инструкции составляют тело функции: они выполняются при каждом вызове функции.
В следующем примере показано несколько определений функций в виде инструкций и выражений. Обратите внимание, что определения функций в виде выражений удобно использовать, только если они являются частью более крупных выражений, таких как присваивание или вызов функции, которые выполняют некоторые действия с помощью вновь объявленной функции:
Обратите внимание, что в выражениях определения функций имя функции может отсутствовать. Инструкция объявления функции фактически объявляет переменную и присваивает ей объект функции.
Выражение определения функции, напротив, не объявляет переменную. Однако в выражениях определения допускается указывать имя функции, как в функции вычисления факториала выше, которое может потребоваться в теле функции для вызова себя самой. Если выражение определения функции включает имя, данное имя будет ссылаться на объект функции в области видимости этой функции. Фактически имя функции становится локальной переменной, доступной только в теле функции. В большинстве случаев имя функции не требуется указывать в выражениях определения, что делает определения более компактными.
Обратите внимание, что большинство (но не все) функций в примере содержат инструкцию return. Инструкция return завершает выполнение функции и выполняет возврат значения своего выражения (если указано) вызывающей программе. Если выражение в инструкции return отсутствует, она возвращает значение undefined. Если инструкция return отсутствует в функции, интерпретатор просто выполнит все инструкции в теле функции и вернет вызывающей программе значение undefined.
Большинство функций в примере вычисляют некоторое значение, и в них инструкция return используется для возврата этого значения вызывающей программе. Функция printprops() несколько отличается в этом смысле: ее работа заключается в том, чтобы вывести имена свойств объекта. Ей не нужно возвращать какое-либо значение, поэтому в функции отсутствует инструкция return. Функция printprops() всегда будет возвращать значение undefined. (Функции, не имеющие возвращаемого значения, иногда называются процедурами.)
Вызов функций
Программный код, образующий тело функции, выполняется не в момент определения функции, а в момент ее вызова. Вызов функций выполняется с помощью выражения вызова. Выражение вызова состоит из выражения обращения к функции, которое возвращает объект функции, и следующими за ним круглыми скобками со списком из нуля или более выражений-аргументов, разделенных запятыми, внутри.
Если выражение обращения к функции является выражением обращения к свойству — если функция является свойством объекта или элементом массива (т.е. методом) — тогда выражение вызова является выражением вызова метода. В следующем фрагменте демонстрируется несколько примеров выражений вызова обычных функций:
При вызове функции вычисляются все выражения-аргументы (указанные между скобками), и полученные значения используются в качестве аргументов функции. Эти значения присваиваются параметрам, имена которых перечислены в определении функции. В теле функции выражения обращений к параметрам возвращают значения соответствующих аргументов.
При вызове обычной функции возвращаемое функцией значение становится значением выражения вызова. Если возврат из функции происходит по достижении ее конца интерпретатором, возвращается значение undefined. Если возврат из функции происходит в результате выполнения инструкции return, возвращается значение выражения, следующего за инструкцией return, или undefined, если инструкция return не имеет выражения.
Метод — это не что иное, как функция, которая хранится в виде свойства объекта. Если имеется функция func и объект obj, то можно определить метод объекта obj с именем method, как показано ниже:
Чаще всего при вызове методов используется форма обращения к свойствам с помощью оператора точки, однако точно так же можно использовать форму обращения к свойствам с помощью квадратных скобок. Например, оба следующих выражения являются выражениями вызова методов:
Аргументы и возвращаемое значение при вызове метода обрабатываются точно так же, как при вызове обычной функции. Однако вызов метода имеет одно важное отличие: контекст вызова. Выражение обращения к свойству состоит из двух частей: объекта (в данном случае obj) и имени свойства (method). В подобных выражениях вызова методов объект obj становится контекстом вызова, и тело функции получает возможность ссылаться на этот объект с помощью ключевого слова this. Например:
Методы и ключевое слово this занимают центральное место в парадигме объектно-ориентированного программирования. Любая функция, используемая как метод, фактически получает неявный аргумент — объект, относительно которого она была вызвана. Как правило, методы выполняют некоторые действия с объектом, и синтаксис вызова метода наглядно отражает тот факт, что функция оперирует объектом.
Обратите внимание: this — это именно ключевое слово, а не имя переменной или свойства. Синтаксис JavaScript не допускает возможность присваивания значений элементу this.
Аргументы и параметры функций
В языке JavaScript, в определениях функций не указываются типы параметров, а при вызове функций не выполняется никаких проверок типов передаваемых значений аргументов. Фактически при вызове функций в языке JavaScript не проверяется даже количество аргументов. В подразделах ниже описывается, что происходит, если число аргументов в вызове функции меньше или больше числа объявленных параметров. В них также демонстрируется, как можно явно проверить типы аргументов функции, если необходимо гарантировать, что функция не будет вызвана с некорректными аргументами.
Необязательные аргументы
Когда число аргументов в вызове функции меньше числа объявленных параметров, недостающие аргументы получают значение undefined. Часто бывает удобным писать функции так, чтобы некоторые аргументы были необязательными и могли опускаться при вызове функции. В этом случае желательно предусмотреть возможность присваивания достаточно разумных значений по умолчанию параметрам, которые могут быть опущены. Например:
Обратите внимание, что при объявлении функций необязательные аргументы должны завершать список аргументов, чтобы их можно было опустить. Программист, который будет писать обращение к вашей функции, не сможет передать второй аргумент и при этом опустить первый: он будет вынужден явно передать в первом аргументе значение undefined. Обратите также внимание на комментарий /* необязательный */ в определении функции, который подчеркивает тот факт, что параметр является необязательным.
Списки аргументов переменной длины
Если число аргументов в вызове функции превышает число имен параметров, функция лишается возможности напрямую обращаться к неименованным значениям. Решение этой проблемы предоставляет объект Arguments. В теле функции идентификатор arguments ссылается на объект Arguments, присутствующий в вызове. Объект Arguments — это объект, подобный массиву, позволяющий извлекать переданные функции значения по их номерам, а не по именам.
Предположим, что была определена функция func, которая требует один аргумент x. Если вызвать эту функцию с двумя аргументами, то первый будет доступен внутри функции по имени параметра x или как arguments[0]. Второй аргумент будет доступен только как arguments[1]. Кроме того, подобно настоящим массивам, arguments имеет свойство length, определяющее количество содержащихся элементов. То есть в теле функции func, вызываемой с двумя аргументами, arguments.length имеет значение 2.
Объект Arguments может использоваться с самыми разными целями. Следующий пример показывает, как с его помощью проверить, была ли функция вызвана с правильным числом аргументов, — ведь JavaScript этого за вас не сделает:
Обратите внимание, что зачастую нет необходимости проверять количество аргументов, как в данном примере. Поведение по умолчанию интерпретатора JavaScript отлично подходит для большинства случаев: отсутствующие аргументы замещаются значением undefined, а лишние аргументы просто игнорируются.
Объект Arguments иллюстрирует важную возможность JavaScript-функций: они могут быть написаны таким образом, чтобы работать с любым количеством аргументов. Следующая функция принимает любое число аргументов и возвращает значение самого большого из них (аналогично ведет себя встроенная функция Math.max()):
Функции, подобные этой и способные принимать произвольное число аргументов, называются . Этот термин возник вместе с появлением языка программирования C.
Обратите внимание, что функции с переменным числом аргументов не должны допускать возможность вызова с пустым списком аргументов. Будет вполне разумным использовать объект arguments[] при написании функции, ожидающей получить фиксированное число обязательных именованных аргументов, за которыми может следовать произвольное число необязательных неименованных аргументов.
Не следует забывать, что arguments фактически не является массивом — это объект Arguments. В каждом объекте Arguments имеются пронумерованные элементы массива и свойство length, но с технической точки зрения это не массив. Лучше рассматривать его как объект, имеющий некоторые пронумерованные свойства.
Помимо элементов своего массива объект Arguments определяет свойства callee и caller. При попытке изменить значения этих свойств в строгом режиме ECMAScript 5 гарантированно возбуждается исключение TypeError. Однако в нестрогом режиме стандарт ECMAScript утверждает, что свойство callee ссылается на выполняемую в данный момент функцию. Свойство caller не является стандартным, но оно присутствует во многих реализациях и ссылается на функцию, вызвавшую текущую.
Свойство caller можно использовать для доступа к стеку вызовов, а свойство callee особенно удобно использовать для рекурсивного вызова неименованных функций:
Свойства и методы функций
Мы видели, что в JavaScript-программах функции могут использоваться как значения. Оператор typeof возвращает для функций строку «function», однако в действительности функции в языке JavaScript — это особого рода объекты. А раз функции являются объектами, то они имеют свойства и методы, как любые другие объекты. Существует даже конструктор Function(), который создает новые объекты функций. В следующих подразделах описываются свойства и методы функций.
Свойство length
В теле функции свойство arguments.length определяет количество аргументов, переданных функции. Однако свойство length самой функции имеет иной смысл. Это свойство, доступное только для чтения, возвращает количество аргументов, которое функция ожидает получить — число объявленных параметров.
В следующем фрагменте определяется функция с именем check(), получающая массив аргументов arguments от другой функции. Она сравнивает свойство arguments.length (число фактически переданных аргументов) со свойством arguments.callee.length (число ожидаемых аргументов), чтобы определить, передано ли функции столько аргументов, сколько она ожидает. Если значения не совпадают, генерируется исключение. За функцией check() следует тестовая функция func(), демонстрирующая порядок использования функции check():
Свойство prototype
Любая функция имеет свойство prototype, ссылающееся на объект, известный как объект прототипа. Каждая функция имеет свой объект прототипа. Когда функция используется в роли конструктора, вновь созданный объект наследует свойства этого объекта прототипа.
Прототипы и свойство prototype обсуждались в предыдущей статье.
Методы call() и apply()
Методы call() и apply() позволяют выполнять косвенный вызов функции, как если бы она была методом некоторого другого объекта. Первым аргументом обоим методам, call() и apply(), передается объект, относительно которого вызывается функция; этот аргумент определяет контекст вызова и становится значением ключевого слова this в теле функции. Чтобы вызвать функцию func() (без аргументов) как метод объекта obj, можно использовать любым из методов, call() или apply():
Любой из этих способов вызова эквивалентен следующему фрагменту (где предполагается, что объект obj не имеет свойства с именем m):
В строгом режиме ECMAScript 5 первый аргумент методов call() и apply() становится значением this, даже если это простое значение, null или undefined. В ECMAScript 3 и в нестрогом режиме значения null и undefined замещаются глобальным объектом, а простое значение — соответствующим объектом-оберткой.
Все остальные аргументы метода call(), следующие за первым аргументом, определяющим контекст вызова, передаются вызываемой функции. Метод apply() действует подобно методу call(), за исключением того, что аргументы для функции передаются в виде массива. Если функция способна обрабатывать произвольное число аргументов, метод apply() может использоваться для вызова такой функции в контексте массива произвольной длины.
В следующем примере демонстрируется практическое применение метода call():
Метод bind()
Метод bind() впервые появился в ECMAScript 5, но его легко имитировать в ECMAScript 3. Как следует из его имени, основное назначение метода bind() состоит в том, чтобы связать (bind) функцию с объектом. Если вызвать метод bind() функции func и передать ему объект obj, он вернет новую функцию. Вызов новой функции (как обычной функции) выполнит вызов оригинальной функции func как метода объекта obj. Любые аргументы, переданные новой функции, будут переданы оригинальной функции. Например:
Такой способ связывания легко реализовать в ECMAScript 3, как показано ниже:
Метод bind() в ECMAScript 5 не просто связывает функцию с объектом. Он также выполняет частичное применение: помимо значения this связаны будут все аргументы, переданные методу bind() после первого его аргумента. Частичное применение — распространенный прием в функциональном программировании и иногда называется каррингом (currying).
Какое свойство функции возвращает массив аргументов
Функции в JavaScript. Возврат значения. Параметры.
Объявление и вызов функции
Один из способ объявления функции выглядит так.
Мы объявляем функцию add с двумя параметрами — x и y . Функция возвращает сумму этих параметров.
Вызов функции выполняется следующим образом.
Если явно не указывать возвращаемое значение, как в этом примере, функция вернёт undefined .
Функции можно вызывать с любым количеством аргументов.
Если параметр не передан при вызове, ему будет присвоено значение undefined .
То же самое справедливо для функции с несколькими аргументами.
Мы можем проверить, передан ли параметр, и если нет, задать ему значение по умолчанию.
При объявлении функции необязательные аргументы, как правило, располагают в конце списка.
Зачастую для задания значения по умолчанию используют более короткую форму с импользованием оператора || .
Этот способ следует использовать с осторожностью. Если параметр может принимать значения, приводимые к false — например, 0 , » или null , они будут перезаписаны значением по умолчанию.
В некоторых языках (например, в python), при вызове функции можно передавать именованные аргументы.
Это удобно по нескольким причинам. Во-первых, в момент вызова мы видим, для чего используется тот или иной аргумент. Во-вторых, становится неважным порядок передачи аргументов. Это особенно удобно, когда у функции есть несколько необязательных аргументов.
В JavaScript мы можем имитировать именованные аргументы с помощью литерала объекта.
Обратите внимание на скобки — на самом деле мы передаём в функцию один аргумент — объект, свойствами которого являются наши как-бы именованные аргументы.
Объявление функции будет выглядеть слудующим образом.
Однако, у такого подхода есть несколько недостатков:
- аргументы нужно вызывать через точку (как свойства объекта)
- по сигнатуре функции нельзя понять, с какими параметрами она вызывается
Поэтому такой подход не следует использовать повсеместно. На практике его обычно применяют, когда функция принимает большое количество необязательных конфигурационных параметров.
Мы также можем передать больше аргументов, чем определено в функции. Избыточные аргументы будут проигнорированы.
Внутри функции доступна специальная переменная arguments , которая позволяет получить доступ ко всем переданным аргументам.
С его помощью мы можем объявить функцию, принимающую любое количество аргументов.
Например, эта функция суммирует все переданные при вызове числа.
По историческим причинам arguments — не массив, а так называемый array-like object. Поэтому у него нет методов массива, таких как forEach или map .
К счастью, есть способ преобразовать его к массиву с помощью следующей конструкции.
Тут нам играет на руку динамическая природа языка JavaSctipt. Нам понадобится метод slice , который может использоваться для копирования массива. Мы берём этот метод у только что созданного массива, и вызываем его на нашем объекте.
Эта конструкция аналогична следующей:
В следующих лекциях мы более подробно поговорим о методе call .
Рассмотрим следующий пример. Нам нужно найти минимальное значение из элементов, которые лежат в массиве numbers .
У нас есть функция Math.min , но она принимает несколько аргументов. Если просто передать массив в функцию — результат будет отличаться от наших ожиданий.
На помощь нам приходит метод apply .
Первым аргументом метод принимает так называемый контекст — объект, на который будет указывать ключевое слово this внутри функции. О контексте и ключевом слове this мы подробнее поговорим в следующих лекциях, а пока просто передадим первым аргументом null .
В качестве второго аргумента метод принимает массив, элементы которого будут переданы в функцию.
Другой полезный метод — bind , позволяет выполнить так называемое частичное применение функции.
Частичное применение — это процесс предачи части аргументов функции, который возвращает другую функцию, принимающую оставшиеся аргументы (функцию меньшей арности).
Рассмотрим функцию возведения в степень — Math.pow . Она принимает два аргумента.
C помощью метода bind мы можем передать только первый аргумент и получить функцию, возводящую в степень определённой число — в нашем случае, двойку.
Функции — объекты первого класса
Функции в JavaScript являются объектами первого класса. Это значит, что функции являются таким же полноценным типом данных, как число, строка или объект.
Функцию можно положить в переменную:
Функуию можно передать в качестве аргумента другой функции:
Наконец, функция может быть возвращена результате выполнения другой функции:
Способы объявления функции
В начале лекции мы говорили об одном способе объявления функции. Он называется function declaration.
Функция, определённая таким образом, создаётся на этапе интерпретации программы, то есть ещё до начала выполнения кода.
Это приводит к эффекту, называемому hoisting, то есть всплытие или подём. Проявляется он в том, что функцию можно вызывать до её объявления.
Это происходит потому, что интерпретатор поднимает объявление функции над выполняемым кодом, и исходный код приобретает следующий вид:
Второй способ объявления функции называется function expression и выглядит так:
В этом примере мы создаём функцию без имени — так называемую «анонимную функцию» и кладём её в переменную add .
Несмотря на общую схожесть с предыдущим вариантом, есть одно существенное различие — эта функция создаётся в момент выполнения кода, поэтому её нельзя использовать до определения.
Функция, объявленная с помощью function expression, не обязательно должна быть анонимной. Мы можем указать для неё идентификатор.
В отличие от function declaration, такой идентификатор будет доступен только внутри функции, но не виден снаружи.
Это может быть полезно при определении рекурсивных функций. Такие функции могут вызывать сами себя.
Для примера рассмотрим функцию вычисления факториала.
Мы рассмотрели два варианта объявления функции. Какой из них лучше?
Оба варианта полностью допустимы. В общем случае можно использовать первый спобоб — function declaration. Этот способ обладает более простым синтаксисом, а также позволяет использовать эффект всплытия.
Есть и ещё один способ объявить функцию, но он встречается достаточно редко.
Мы можем использовать конструктор Function . Этот способ может пригодиться, если требуется создать тело функции на этапе выполнения кода.
Область видимости функции
Область видимости переменной — это часть кода, в пределах которой эта переменная доступна.
В Javascript область видимости переменной ограничивается функцией.
Определяя функцию внутри другой функции, мы создаём новую область видимости. Переменная из внешней области видимости доступна во вложенной
Если во внутренней области видимости объявить переменную с тем же именем, что и во внешней, она перекроет переменную из внешней области видимости. Этот эффект называется shadowing (затенение).
В отличие от других языков, блок не создаёт область видимости:
В этом примере срабатывает механизм всплытия, о котором мы говорили ранее.
Интерпретатор поднимает объявление переменной к началу области видимости, то есть к началу функции:
Иногда возникает необходимость искуственно создать область видимости. Например, если мы хотим ограничить доступ к некторым переменным.
Для этого можно использовать способ, называемый «немедленно вызываемой функцией» или IIFE (immediately-invoked function expression).
Мы создаём функцию, чтобы ввести новую область видимости. И сразу же после создания вызываем её.
Скобки фокруг функции нужны для того, чтобы интерпретатор понял, что мы хотим использовать function expression.
Если попробовать немедленно вызвать функцию, объявленную с помощью function declaration, мы получим ошибку синтаксиса — язык не разрешает такую конструкцию.
Чтобы исправить ситуацию, нам нужно поместить любой символ перед ключевым словом function . Сделать это мы можем любым способом:
Новые возможности языка
Рассмотрим возможности, которы вносит новый стандарт языка ECMAScript 2015.
Блочная область видимости
Для создания области видимости нужно было использовать IIFE.
Теперь можно объявить переменную с блочной областью видимости с помощью ключевого слова let .
Значения параметра по умолчанию
Для того, чтобы установить значение параметра по умолчанию, нужно было проверять его значение.
Теперь можно задать значение по умолчанию в сигнатуре функции.
Функции с произвольным числом аргументов
Для доступа к произвольному числу аргументов нужно было обращаться к переменной arguments .
Теперь можно использовать оператор . чтобы получить массив переданных аргументов.
Одним из недостатков именованных аргументов являлась необходимость обращаться к параметрам через точку.
Теперь мы можем извлечь значения из переданного объекта прямо в сигнатуре функции: