У зоне бачнасці любой функцыі JavaScript ёсць доступ да адмысловай пераменнай
arguments. Гэтая пераменная утрымлівае спіс усіх аргументаў, што былі
перададзеныя функцыі.
Заўвага: У выпадку, калі
argumentsужо быў створаны ўнутры зоны бачнасці функцыі праз выразvar, або з'яўляецца фармальным параметрам, аб'ектargumentsне будзе створаны.
Аб'ект arguments не з'яўляецца спадкаемцам Array. Ён мае падабенствы
з масівам, напрыклад уласцівасць length. Але ён не ўспадкоўвае Array.prototype,
а ўяўляе з сябе Object.
Таму немагчыма выклікаць стандартныя метады push, pop або slice
у аб'екта arguments. Тым не менш, ітэрацыя з звычайным цыклам for працуе карэктна.
Неабходна канвертаваць яго ў сапраўдны аб'ект Array, каб прымяніць стандартныя
метады масіваў.
Ніжэйпрыведезны код верне новы масіў, які будзе ўтрымліваць усе элементы аб'екта
arguments.
Array.prototype.slice.call(arguments);
Такая канвертацыя марудная, яе не рэкамендуецца выкарыстоўваць у крытычных у плане прадукцыйнасці частках кода.
Ніжэй прадстаўлены рэкамендаваны спосаб перадачы аргументаў з адной функцыі ў іншую.
function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// тут робім што-небудзь
}
Яшчэ адзін прыём — гэта выкарыстанне call і apply разам, каб ператварыць метады,
што выкарыстоўваюць значэнне this як і свае аргументы, у звычайныя функцыі,
што выкарыстоўваюць толькі аргументы.
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullname = function(joiner, options) {
options = options || { order: "western" };
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};
// Ствараем незвязаную версію "fullname", што можа быць выкарыстана з любым
// аб'ектам, які мае ўласцівасці 'first' і 'last', перададзеным у якасці
// першага параметра. Гэтую абгортку не трэба будзе мяняць, калі колькасць або
// парадак аргументаў fullname зменяцца.
Person.fullname = function() {
// Result: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};
var grace = new Person("Grace", "Hopper");
// 'Grace Hopper'
grace.fullname();
// 'Turing, Alan'
Person.fullname({ first: "Alan", last: "Turing" }, ", ", { order: "eastern" });
Аб'ект arguments стварае гэтэр і сэтэр як да кожнай са сваіх уласцівасцяў,
так і да фармальных параметраў функцыі.
У выніку змена значэння фармальнага параметра зменіць таксама адпаведную ўласцівасць
аб'екта arguments, і наадварот.
function foo(a, b, c) {
arguments[0] = 2;
a; // 2
b = 4;
arguments[1]; // 4
var d = c;
d = 9;
c; // 3
}
foo(1, 2, 3);
Адзінае, калі arguments не ствараецца, — гэта калі ёсць фармальны аргумент функцыі
або пераменная ўнутры яе з такім іменем. Не важна, выкарыстоўваюцца яны ці не.
Як гэтэры, так і сэтэры ствараюцца заўсёды, таму іх выкарыстоўванне не мае амаль ніякага ўплыву на прадукцыйнасць.
Заўвага для ES5: гэтэры і сэтэры не ствараюцца ў строгім рэжыме.
Тым не менш, ёсць адна рэч, якая можа жахліва знізіць прадукцыйнасць у сучасных
рухавіках JavaScript — гэта выкарыстанне arguments.callee.
function foo() {
arguments.callee; // робім што-небудзь з функцыяй foo
arguments.callee.caller; // і з функцыяй, якая выклікала foo
}
function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // Звычайна ўстаўляецца...
}
}
У вышэйпрыведзеным кодзе foo больш не можа быць устаўлена, бо ёй трэба
ведаць аб сабе і аб функцыі, што яе выклікала. Гэта не толькі знішчае павышэнне
прадукцыйнасці, якое магло адбыцца дзякуючы ўстаўцы, але і парушае інкапсуляцыю, бо
функцыя цяпер залежыць ад спецыфічнага кантэксту, які яе выклікае.
Выкарыстоўванне arguments.callee або яго ўласцівасцяў вельмі непажадана.
Заўвага для ES5: У строгім рэжыме
arguments.calleeкіне памылкуTypeError, бо яго выкарыстанне аб'яўлена састарэлым.