Skip to content

Latest commit

 

History

History
130 lines (94 loc) · 6.52 KB

File metadata and controls

130 lines (94 loc) · 6.52 KB

Аб'ект arguments

У зоне бачнасці любой функцыі JavaScript ёсць доступ да адмысловай пераменнай arguments. Гэтая пераменная утрымлівае спіс усіх аргументаў, што былі перададзеныя функцыі.

Заўвага: У выпадку, калі arguments ужо быў створаны ўнутры зоны бачнасці функцыі праз выраз var, або з'яўляецца фармальным параметрам, аб'ект arguments не будзе створаны.

Аб'ект arguments не з'яўляецца спадкаемцам Array. Ён мае падабенствы з масівам, напрыклад уласцівасць length. Але ён не ўспадкоўвае Array.prototype, а ўяўляе з сябе Object.

Таму немагчыма выклікаць стандартныя метады push, pop або slice у аб'екта arguments. Тым не менш, ітэрацыя з звычайным цыклам for працуе карэктна. Неабходна канвертаваць яго ў сапраўдны аб'ект Array, каб прымяніць стандартныя метады масіваў.

Канвертацыя ў масіў

Ніжэйпрыведезны код верне новы масіў, які будзе ўтрымліваць усе элементы аб'екта arguments.

Array.prototype.slice.call(arguments);

Такая канвертацыя марудная, яе не рэкамендуецца выкарыстоўваць у крытычных у плане прадукцыйнасці частках кода.

Перадача 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, бо яго выкарыстанне аб'яўлена састарэлым.