Arguments javascript что это

Псевдомассив аргументов «arguments»

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

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

function go(a,b) < alert("a="+a+", b="+b); >go(1); // a=1, b=undefined go(1,2); // a=1, b=2 go(1,2,3); // a=1, b=2, третий аргумент не вызовет ошибку

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

function log(a) < . >function log(a, b, c) < . >log(a); // вызовется первая функция log(a, b, c); // вызовется вторая функция

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

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

А уже внутри она может посмотреть, с чем вызвана и по-разному отработать.

В примере выше второе объявление log просто переопределит первое.

Доступ к «лишним» аргументам

Как получить значения аргументов, которых нет в списке параметров?

Доступ к ним осуществляется через «псевдо-массив» arguments.

Он содержит список аргументов по номерам: arguments[0] , arguments[1] …, а также свойство length .

Например, выведем список всех аргументов:

function sayHi() < for (var i = 0; i < arguments.length; i++) < alert( "Привет, " + arguments[i] ); >> sayHi("Винни", "Пятачок"); // 'Привет, Винни', 'Привет, Пятачок'

Все параметры находятся в arguments , даже если они есть в списке. Код выше сработал бы также, будь функция объявлена sayHi(a,b,c) .

В старом стандарте JavaScript псевдо-массив arguments и переменные-параметры ссылаются на одни и те же значения.

В результате изменения arguments влияют на параметры и наоборот.

В современной редакции стандарта это поведение изменено. Аргументы отделены от локальных переменных:

Если вы не используете строгий режим, то чтобы переменные не менялись «неожиданно», рекомендуется никогда не изменять arguments .

arguments – это не массив

Частая ошибка новичков – попытка применить методы Array к arguments . Это невозможно:

Дело в том, что arguments – это не массив Array .

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

Впрочем, никто не мешает сделать обычный массив из arguments , например так:

var args = []; for (var i = 0; i

Такие объекты иногда называют «коллекциями» или «псевдомассивами».

Пример: копирование свойств copy(dst, src1, src2. )

Иногда встаёт задача – скопировать в существующий объект свойства из одного или нескольких других.

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

copy(dst, src1, src2…) Копирует свойства из объектов src1, src2. в объект dst . Возвращает получившийся объект.

    Для объединения нескольких объектов в один:

var vasya = < age: 21, name: 'Вася', surname: 'Петров' >; var user = < isAdmin: false, isEmailConfirmed: true >; var student = < university: 'My university' >; // добавить к vasya свойства из user и student copy(vasya, user, student); alert( vasya.isAdmin ); // false alert( vasya.university ); // My university
// скопирует все свойства в пустой объект var userClone = copy(<>, user);
function copy() < var dst = arguments[0]; for (var i = 1; i < arguments.length; i++) < var arg = arguments[i]; for (var key in arg) < dstArguments javascript что это = argArguments javascript что это; >> return dst; >

Здесь первый аргумент copy – это объект, в который нужно копировать, он назван dst . Для упрощения доступа к нему можно указать его прямо в объявлении функции:

function copy(dst) < // остальные аргументы остаются безымянными for (var i = 1; i < arguments.length; i++) < var arg = arguments[i]; for (var key in arg) < dstArguments javascript что это = argArguments javascript что это; >> return dst; >

Аргументы по умолчанию через ||

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

Зачастую в случае отсутствия аргумента мы хотим присвоить ему некоторое «стандартное» значение или, иначе говоря, значение «по умолчанию». Это можно удобно сделать при помощи оператора логическое ИЛИ || .

Например, функция showWarning , описанная ниже, должна показывать предупреждение. Для этого она принимает ширину width , высоту height , заголовок title и содержимое contents , но большая часть этих аргументов необязательна:

function showWarning(width, height, title, contents) < width = width || 200; // если не указана width, то width = 200 height = height || 100; // если нет height, то height = 100 title = title || "Предупреждение"; //. >

Это отлично работает в тех ситуациях, когда «нормальное» значение параметра в логическом контексте отлично от false . В коде выше, при передаче width = 0 или width = null , оператор ИЛИ заменит его на значение по умолчанию.

А что, если мы хотим использовать значение по умолчанию только если width === undefined ? В этом случае оператор ИЛИ уже не подойдёт, нужно поставить явную проверку:

function showWarning(width, height, title, contents) < if (width === undefined) width = 200; if (height === undefined) height = 100; if (title === undefined) title = "Предупреждение"; //. >

Устаревшее свойство arguments.callee

Это свойство устарело, при use strict оно не работает.

Единственная причина, по которой оно тут – это то, что его можно встретить в старом коде, поэтому о нём желательно знать.

Современная спецификация рекомендует использовать именованные функциональные выражения (NFE).

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

Эти два примера будут работать одинаково:

// подвызов через NFE var factorial = function f(n) < return n==1 ? 1 : n*f(n-1); >; // подвызов через arguments.callee var factorial = function(n) < return n==1 ? 1 : n*arguments.callee(n-1); >;

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

arguments.callee.caller

Устаревшее свойство arguments.callee.caller хранит ссылку на функцию, которая вызвала данную.

Это свойство было в старом стандарте, при use strict оно не работает, как и arguments.callee .

Также ранее существовало более короткое свойство arguments.caller . Но это уже раритет, оно даже не кросс-браузерное. А вот свойство arguments.callee.caller поддерживается везде, если не использован use strict , поэтому в старом коде оно встречается.

f1(); function f1() < alert( arguments.callee.caller ); // null, меня вызвали из глобального кода f2(); >function f2() < alert( arguments.callee.caller ); // f1, функция, из которой меня вызвали f3(); >function f3() < alert( arguments.callee.caller ); // f2, функция, из которой меня вызвали >

В учебнике мы это свойство также не будем использовать.

«Именованные аргументы»

Именованные аргументы – альтернативная техника работы с аргументами, которая вообще не использует arguments .

Некоторые языки программирования позволяют передать параметры как-то так: f(width=100, height=200) , то есть по именам, а что не передано, тех аргументов нет. Это очень удобно в тех случаях, когда аргументов много, сложно запомнить их порядок и большинство вообще не надо передавать, по умолчанию подойдёт.

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

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

function showWarning(options) < var width = options.width || 200; // по умолчанию var height = options.height || 100; var contents = options.contents || "Предупреждение"; // . >

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

Сравним это с передачей аргументов через список:

showWarning(null, null, "Предупреждение!"); // мысль программиста "а что это за null, null в начале? ох, надо глядеть описание функции"

Не правда ли, объект – гораздо проще и понятнее?

Ещё один бонус кроме красивой записи – возможность повторного использования объекта аргументов:

var opts = < width: 400, height: 200, contents: "Текст" >; showWarning(opts); opts.contents = "Другой текст"; showWarning(opts); // вызвать с новым текстом, без копирования других аргументов

Именованные аргументы применяются во многих JavaScript-фреймворках.

Итого

  • Полный список аргументов, с которыми вызвана функция, доступен через arguments .
  • Это псевдомассив, то есть объект, который похож на массив, в нём есть нумерованные свойства и length , но методов массива у него нет.
  • В старом стандарте было свойство arguments.callee со ссылкой на текущую функцию, а также свойство arguments.callee.caller , содержащее ссылку на функцию, которая вызвала данную. Эти свойства устарели, при use strict обращение к ним приведёт к ошибке.
  • Для указания аргументов по умолчанию, в тех случаях, когда они заведомо не false , удобен оператор || .

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

Возможен и гибридный подход, при котором первый аргумент обязателен, а второй – options , который содержит всевозможные дополнительные параметры:

function showMessage(text, options) < // показать сообщение text, настройки показа указаны в options >

Источник

Магия JavaScript: arguments

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

А также покажу интересную идею-библиотеку

function test (foo, bar) < Args(arguments).defaults(100, 100); return [foo, bar]; >; test( ); // 100, 100 test(15 ); // 15, 100 test(21, 42); // 21, 42 

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

Что такое arguments

Сделать из него массив просто:

var array = Array.prototype.slice.call(arguments, 0); // или покороче, но менее производительно: var array = [].slice.call(arguments, 0); 

Мы вызываем метод slice прототипа Array от лица arguments .

Что есть в arguments

var count = function () < console.log(arguments.length); >; count(); // 0 count(first, second); // 2 

Не забывайте, что у каждой функции тоже есть свойство length , которое указывает на то, сколько элементов объявлено в её заголовке:

function one (foo) <>; function three (foo, bar, qux) <>; console.log( one.length); // 1 console.log(three.length); // 3 

arguments.callee — ссылка на саму функцию.

Таким образом можно проверить, передано ли правильное количество элементов, или нет:

function test (foo, bar, qux) < return arguments.callee.length === arguments.length; >test(1); // false test(1,2,3); // true 

Аргументы в arguments

function test (foo, bar) < console.log(foo, bar); // 'a', 'b' console.log(arguments[0], arguments[1]); // 'a', 'b' >test('a', 'b'); 

Теперь к интересному. Многие не знают, что объект arguments — содержит на самом деле ссылки, а не значения, и тесно связан с аргументами:

При этом связь достаточно крепкая:

function foo (qux) < change(arguments); return qux; >; function change(a) < a[0] = 42; >foo(10); // 42 

Что из этого можно получить?

function ($foo = 30, $bar = 'test')

В javascript оно будет выглядеть как-то так:

Зная особенности arguments можно создать красивый интерфейс:

function test(foo, bar) < Args(arguments).defaults(30, 'test'); console.log(foo, bar) >test(); // 30, 'test' 
 function Args (args) < if (this instanceof Args) < this.args = args; >else < // Если создано не через new, а просто вызвана функция, создаем и возвращаем новый объект return new Args(args); >>; Args.prototype = < defaults: function () < var defaults = arguments; for (var i = defaults.length; i--;) < if (typeof args[i] === 'undefined') args[i] = defaults[i]; >return this; > >; 

Аналогично можно сделать автоматическое приведение типов:

function test(foo) < Args(arguments) .defaults(10) .cast(Number); console.log(foo) >test('0100'); // 100 
function test(foo, bar) < Args(arguments).types(Foo, Bar); // code >test(new Foo(), new Bar()); test(1, 2); // Error 

Из интересных идей — сообщение, что все аргументы обязательны:

function test (foo, bar, qux) < Args(arguments).allRequired(); >test(1,2,3); // success test(1,2); // Error: 3 args required, 2 given 

Заключение

Все эти идеи и возможности (и даже больше) я оформил в библиотеку — Args.js.
Согласен, что кое-какие вещи (как TypeHinting) не совсем подходят к идеологии языка. В то же время например defaults — очень удобная штука, имхо.
Пока что это прототип и, перед тем как вы будете его использовать — будьте уверены, что оно вам действительно нужно, а не что вы просто стараетесь из прекрасного языка сделать что-то похожее на C#.
Предлагаю обсудить, покритиковать код, найти пару багов и закоммитить несколько строк кода)

Args.js

К сожалению, из-за бага в трёх популярных браузерах(IE, Fx, Opera) я не смог добиться желаемого эффекта, полноценно самое вкусное заработало только в Chrome (ну по крайней мере в node.js работать будет)). Надеюсь, решим эту проблему вместе.

UPD: В комментах выяснили, что таки это бага Хрома, но, зато, какая приятная! Спасибо jamayka

Источник

Читайте также:  Html формы input type text
Оцените статью