Чи існує максимальна кількість аргументів, які можуть приймати функції JavaScript?


80

Я знаю, що функції JavaScript можуть приймати будь-яку кількість аргументів.

function f(){};
f(1,2,3,4 /*...*/);

Але мені цікаво, чи насправді існує межа, скільки "будь-якого" може бути?

Наприклад, припустимо, я наводжу мільйон аргументів f(). Це спрацювало б? Або перекладач килів?

Я здогадуюсь, що максимум є (a) специфічним для реалізації або (b) (2^32)-1, оскільки argumentsоб’єкт схожий на масив.

Я не бачу цього згаданого в специфікації мови, але, можливо, я не підключаю деякі крапки.


3
Крім того, БУДЬ-ЯКУ велику послідовність даних, подібних до цього, слід передавати як єдиний аргумент, що є масивом, а не як окремі аргументи, тому не потрібно робити цілу копію великого набору даних лише для виклику функції. Це має бути академічна вправа, а не те, з чим можна зіткнутися з належними практиками розвитку.
jfriend00

1
@ jfriend00, не забувайте про Function.prototype.apply. stackoverflow.com/questions/1379553/…
Пол Дрейпер,

@PaulDraper - Я знаю про це .apply(), але він також робить копію вхідного масиву. Справа в тому, що будь-який інтерфейс, який розраховує прийняти дуже велику кількість аргументів, не повинен оголошуватися так, щоб він вимагав їх передачі як звичайних аргументів. Набагато ефективніше передавати масив, тому не потрібно робити копію даних.
jfriend00

5
@ IngoBürk Це не теоретичне питання! Навіть якщо ви ніколи явно не пишете таку функцію, якщо ви використовуєте оператор розповсюдження ES 2015 та такі функції, як Math.maxабо Array.prototype.concat(...arrayOfArrays)(щоб згладити масив масивів), ви можете дійти до цієї межі динамічно, не написавши функції монстра. Накладні витрати, згадані jfriend00, не завжди мають значення - чіткість коду важливіша, ніж кілька байт пам'яті або циклів процесора, і синтаксис розширення іноді може бути найкращим вибором у цьому відношенні. Подивіться на альтернативи "згладити масив" мого короткого коду ...
Мерре

@ Mörre Мій коментар з березня 2014 р. ES5015 не випускався до червня 2015 р.
Ingo Bürk,

Відповіді:


92

Хоча в специфікації немає нічого конкретного, що обмежує теоретичну максимальну кількість аргументів (на що вказує відповідьзору ). Звичайно, є практичні обмеження. Ці обмеження повністю залежать від реалізації, і, швидше за все, також будуть залежати від того, як ви викликаєте функцію.


Я створив цю скрипку як експеримент.

function testArgs() {
    console.log(arguments.length);
}

var argLen = 0;
for (var i = 1; i < 32; i++) {
    argLen = (argLen << 1) + 1;
    testArgs.apply(null, new Array(argLen));
}

Ось мої результати:

  • Chrome 33.0.1750.154 м: Останнім успішним тестом було 65535 аргументів. Після цього не вдалося:

    Uncaught RangeError: перевищено максимальний розмір стека викликів

  • Firefox 27.0.1: Останнім успішним тестом було 262143 аргументи. Після цього не вдалося:

    RangeError: масив аргументів, переданий у Function.prototype.apply, завеликий

  • Internet Explorer 11: Останнім успішним тестом було 131071 аргумент. Після цього не вдалося:

    RangeError: SCRIPT28: Немає місця в стеку

  • Opera 12.17: Останнім успішним тестом було 1048576 аргументів. Після цього не вдалося:

    Помилка: Function.prototype.apply: argArray завеликий

Звичайно, тут можуть бути інші фактори, і у вас можуть бути різні результати.


І ось альтернативна скрипка, створена за допомогою eval. Знову ж таки, ви можете отримати різні результати.

  • Chrome 33.0.1750.154 м: Останнім успішним тестом було 32767 аргументів. Після цього не вдалося:

    Uncaught SyntaxError: Забагато аргументів у виклику функції (дозволено лише 32766)

    Цей особливо цікавий, тому що Chrome, схоже, бентежить питання про те, скільки аргументів насправді дозволено.

  • Firefox 27.0.1: Останнім успішним тестом було 32767 аргументів. Після цього не вдалося:

    сценарій завеликий

  • Internet Explorer 11: Останнім успішним тестом було 32767 аргументів. Після цього не вдалося:

    RangeError: SCRIPT7: Немає пам’яті

  • Opera 12.17: Останнім успішним тестом було 4194303 аргументи. Після цього не вдалося:

    Недостатньо помяті; сценарій припинено.


Це чудово. Хоча, якщо ви використовуєте applyта надсилаєте аргументи як Array, теоретичний максимум на специфікацію складе 4 294 967 295 елементів незалежно від практичних обмежень (?).
Зберігайте

1
Ваш приклад тестує максимум .apply()аргументів функції, переданих як показано у питанні. Вони не обов'язково однакові. Ось демонстрація, де я створив функцію із рядка за допомогою Functionконструктора. Функція викликає вашу testArgs()функцію, передаючи їй 100 000 аргументів. Просто створення цієї функції не вдаєтьсяSyntaxError: too many function arguments
монстр cookie

@cookiemonster Ви маєте рацію. Існує багато різних факторів, які можуть обмежувати максимальну кількість, і різні методи її виклику можуть дати різні результати. Думаю, мені слід трохи наголосити на першому реченні.
pswg

Так, все залежить від того, що має на увазі OP. Я не уявляю, щоб ввести 100 000 аргументів до функції, тому .apply()це здається більш імовірним. Але тоді він не згадав .apply(), тож, можливо, він планує щось зробити eval.
cookie monster

@GladstoneKeep Correct. Мої тести стосуються з’ясування приблизних практичних обмежень у певному браузері.
pswg

22

ECMAScript 5.1, частина 8.8

Тип List використовується для пояснення оцінки списків аргументів (див. 11.2.4) у нових виразах, у викликах функцій та в інших алгоритмах, де потрібен простий список значень .... Ці послідовності можуть мати будь-яку довжину.

Тож обмежень у стандарті немає. Звичайно, якщо ваш код працює у реальному світі, а не у стандартах, очевидно, існує певна межа (наприклад, кількість частинок у Всесвіті).

Існує два способи передачі параметрів функції.

  • "Буквально": f(a, b, c)
  • З apply (): f.apply(null, [a, b, c])

Цей останній шлях є більш реалістичним сценарієм для великих списків аргументів.

Перейдіть до цього JSFiddle, щоб побачити обмеження для кожного з них для вашого поточного браузера.

Я сам випробував кілька браузерів:

           | apply() | literal
 ----------------------------
Chrome 14  | 131155  |  32767
Chrome 35  | 126213  |  65535
Firefox 30 | 500001  |  65535
IE 9       | 254335  |  65533
IE 10      | 253667  |  65533
IE 11      | 252447  |  65533
Opera 22   | 126063  |  65535
Safari 4   | 524215  | 524205
Safari 7   |  65537  | 522159

Я бачив різницю в багатьох з цих цифр на різних машинах, тому я вважаю, що існують інші фактори, крім просто браузера (ОС?).


Це справжнє питання, а не якісь дрібниці. Реальний приклад:

Бібліотека закриття Google визначила таку функцію.

goog.crypt.byteArrayToString = function(array) {
  return String.fromCharCode.apply(null, array);
};

Це спрацювало, лише якщо довжина рядка була в межах браузера для кількості аргументів, які можна передавати Function.prototype.apply.

Пізніше функція була виправлена , що значно ускладнило функцію.


FYI, існує відкрите питання Webkit, подане в березні 2012 року, де обговорюється обмеження аргументів.


6

Відповідно до стандартної специфікації ECMA Script 5.1 дляList ,

Тип List використовується для пояснення оцінки списків аргументів (див. 11.2.4) у нових виразах, у викликах функцій та в інших алгоритмах, де потрібен простий список значень. Значення типу List - це просто впорядковані послідовності значень. Ці послідовності можуть мати будь-яку довжину.

Отже, стандарт не має жодних обмежень на кількість аргументів і обмежений лише пам'яттю.



1

Це повністю залежить від того, наскільки потужним є клієнт.

Оскільки браузер втратить пам’ять, якщо ви збираєтеся передавати мільйони аргументів.

Кожна змінна містить деяку пам’ять. Отже, браузери не матимуть проблем із виділенням кожної змінної деякої пам’яті, поки у неї самої не буде пам'яті для роботи.


1

Просто використовуйте карту (лише об’єкт) як єдиний параметр. Ви все ще можете використовувати імена параметрів і можете мати скільки завгодно аргументів. Це гарантує вам теоретичну нескінченну кількість аргументів, які ви можете подати, однак ви, очевидно, все ще залишаєтесь обмеженими простором купи.

let infiniteParameters = (w) => console.table(w);

infiniteParameters({
  name1 : "value1",
  name2 : "value2",
  // ...
});

0

Ось як я це перевіряю.

let args = [];

while(true){
    try{
        (() => {})(...args);
        args.push(0);
    }catch(e){
        console.log(e.message);
        console.log(`Number of arguments: ${args.length}`);
        break;
    }
}

0

Відповідно до розділу функцій JavaScript MDN, максимальна кількість параметрів, яку може прийняти функція, становить 255 .

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Defining_functions

param The name of an argument to be passed to the function. A function can have up to 255 arguments.


З тих пір цей розділ було видалено. Можливо, це було неправильно
Дренай
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.