Подтвердить что ты не робот

Javascript функции и аргументы объекта, есть ли затраты

Это обычное место, чтобы увидеть такой код в Интернете и в рамках:

var args = Array.prototype.slice.call(arguments);

При этом вы преобразовываете аргументы Object в реальный Array (так как JS имеет реальные массивы), и он позволяет использовать любые методы массива, которые у вас есть в прототипах Array, которые будут применяться к нему, и т.д. и др.

Я помню, где-то читал, что доступ к объекту arguments напрямую может быть значительно медленнее, чем клон Array, или очевидный выбор именованных аргументов. Есть ли в этом правда и при каких обстоятельствах/браузерах это может привести к штрафу за производительность? Любые статьи по этому вопросу, о которых вы знаете?

обновить интересную находку от http://bonsaiden.github.com/JavaScript-Garden/#function.arguments, которая делает недействительными то, что я читал ранее... Надеюсь, что вопрос получит еще несколько ответов от таких @Ivo Wetzel, которые написали это.

В нижней части этого раздела говорится:

Мифы о действии и истины

Объект arguments всегда создается за исключением двух случаи, когда он объявлен как имя внутри функции или одной из ее формальные параметры. Это не имеет значения используется ли оно или нет.

это противоречит http://www.jspatterns.com/arguments-considered-harmful/, в котором говорится:

Однако не рекомендуется использовать аргументы по причинам:

  • производительность
  • Безопасность

Объект arguments не создается автоматически при каждом вызове функции, механизм JavaScript будет создавать его только по требованию, если он используется. И это творение не является бесплатным с точки зрения производительности. Разница между использованием аргументов и отсутствием использования может быть где-то между 1,5 и 4 раза медленнее, в зависимости от браузера

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

ECMA die-hard Дмитрий Сошников сказал:

Какой именно "движок JavaScript" имел ввиду? Откуда у вас это точное Информация? Хотя, это может быть правдой в некоторых (да, это хорошо оптимизации, так как вся необходимая информация о контекст доступен при разборе код, поэтому theres не нужно создавать аргумент объекта, если он не найден при разборе), но, как вы знаете ECMA-262-3, эти аргументы объект создается каждый раз на входящий в контекст выполнения.

4b9b3361

Ответ 1

Ниже приведено несколько тестов q & d. Использование предопределенного arguments кажется самым быстрым, но это не всегда возможно сделать. Если арность функции неизвестна заранее (поэтому, если функция может или должна принимать переменное количество аргументов), я думаю, что вызов Array.prototype.slice один раз был бы наиболее эффективным способом, потому что в этом случае потеря производительности с использованием объекта arguments является самой минимальной.

Ответ 2

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

function f(x, y) {
    // arguments also include x and y
}

Это, вероятно, самая распространенная проблема: вы хотите иметь остальные аргументы, без тех, которые у вас уже есть в x и y, поэтому вы хотели бы есть что-то вроде этого:

var rest = arguments.slice(2);

но вы не можете, потому что у него нет метода slice, поэтому вам нужно вручную применить Array.prototype.slice.

Я должен сказать, что я не видел преобразования всех аргументов в реальный массив только ради производительности, только как удобство вызова методов Array. Мне нужно было бы сделать некоторые профилирования, чтобы узнать, что на самом деле быстрее, и это может зависеть быстрее для чего, но я предполагаю, что разница не очень важна, если вы не хотите называть методы массива, в этом случае у вас нет выбора, кроме как преобразовать его в реальный массив или применить методы вручную с помощью вызова или применения.

Хорошей новостью является то, что в новых версиях ECMAScript (Harmony?) мы сможем написать именно это:

function f(x, y, ...rest) {
   // ...
}

и мы сможем забыть все эти уродливые обходные пути.

Ответ 3

Я бы возразил против принятого ответа.
Я отредактировал тесты, см. здесь: http://jsperf.com/arguments-performance/6
Я добавил тест для метода slice и тест для копирования памяти в предварительно выделенный массив. Последний в несколько раз эффективнее на моем компьютере. Как вы можете видеть, первые два метода копирования памяти на этой тестовой странице производительности медленны не из-за циклов, а из-за вызова push. В заключение, slice кажется почти худшим методом для работы с arguments (не считая методов push, поскольку они даже не намного короче в коде, чем гораздо более эффективный метод preallocation).
Также может быть интересно, что функция apply ведет себя довольно хорошо и не имеет большого значения производительности.

Первый существующий тест:

function f1(){
    for(var i = 0, l = arguments.length; i < l; i++){
        res.push(arguments[i])
    }
}

Добавлены тесты:

function f3(){
    var len = arguments.length;
    res = new Array(len);
    for (var i = 0; i < len; i++)
         res[i] = arguments[i];
}

function f4(){
    res = Array.prototype.slice.call(arguments);
}

function f5_helper(){
    res = arguments;
}
function f5(){
    f5_helper.apply(null, arguments);
}

function f6_helper(a, b, c, d){
    res = [a, b, c, d];
}
function f6(){
    f6_helper.apply(null, arguments);
}