Есть ли снижение производительности при замене локальных переменных аргументами в Javascript? - PullRequest
6 голосов
/ 06 декабря 2010

Есть ли какое-либо снижение производительности при написании функции, когда локальные операторы var заменяются аргументами? Пример:

function howManyMatch(arr, pattern, /*ignored:*/ i, l, total) {
  l = arr.length;
  total = 0;
  for (i = 0, i < l; i++) {
    if (pattern.test(arr[i]))
      total++;
  return total;
}

Некоторые преимущества:

  • меньший минимизированный размер: нет var операторов;
  • меньше времени, затрачиваемого программистом на попытки использовать как можно меньше var s
  • все локальные переменные определены в одном месте

... и недостатки:

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

Тем не менее, это может быть простой способ для минификатора автоматически выжать больше битов.

Обновление: большой недостаток, не упомянутый до сих пор: если функция вызывается с N параметрами, первые N элементов в arguments будут связаны с первыми N идентификаторами в списке аргументов (см. последняя пуля в 10.1.8 ). Учтите это:

function processStuff(/*ignored:*/i, j, k) {
    // use i/j/k to loop
    // do stuff with the arguments pseudo-array
}

В приведенном выше примере, если вы позвонили processStuff(stuff1, stuff2), установка i и j перезапишет arguments[0] и arguments[1] соответственно.

Ответы [ 5 ]

5 голосов
/ 07 декабря 2010

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

Если необходимо, просто используйте оператор запятую и объявите все свои переменные в одном выражении прямо в начале функции (они все равно поднимаются на это место.

function howManyMatch(arr, pattern) {
  var i, l, total;
  // rest
}

Или вы можете объявить / определить все за один шаг тоже

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i = 0;
  // rest
}
4 голосов
/ 07 декабря 2010

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

Теперь, отвечая на вопрос, Я не думаю, что это повлияет на производительность .

Позвольте мне немного поговорить о процессе создания переменной , он происходит для кода функции, непосредственно перед выполнением функции (обычно известной как «подъем»), во-первых, все Формальные параметры , описанные для функции, привязаны к текущему объекту переменной (текущей области), и они инициализируются значениями, переданными в вызове функции, или undefined, если не предоставлено.

После этого все идентификаторы, принадлежащие всем операторам var в функции, объявляются в текущей области и инициализируются с помощью undefined (обратите внимание, что назначения выполняются после этого, тело функции фактически не является выполняется еще).

Третий шаг - FunctionDeclarations, все идентификаторы объявлений функций привязаны к локальной области, если идентификатор был ранее объявлен, его значение заменяется, например:

(function (a) {
  return typeof a; // "function", not "string"

  function a () {}

})('foo');  // <-- passing a string

Я бы рекомендовал вместо этого просто использовать один оператор var в верхней части функции:

function howManyMatch(arr, pattern) {
  var l = arr.length,
      total = 0, i;
  for (i = 0, i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

Это не просто организует ваш код, это поможет вам предотвратить нежелательные результаты из-за функциональности JavaScript и «подъемной» природы var, некоторые инструменты, такие как JSLint, поощряют это тоже.

1 голос
/ 07 декабря 2010

Я думаю, что читаемость и удобство обслуживания превышают размер файла и микрооптимизацию здесь.Код намного легче читать с ключевым словом var.Кроме того, достаточно одного оператора var для каждой области (в любом случае JavaScript их поднимает). Все локальные переменные доступны везде в локальной области (независимо от порядка, в котором они были объявлены).Поэтому все локальные переменные должны быть объявлены в одной и той же позиции (в начале локальной области видимости) для лучшей читаемости.Эти четыре байта для оператора var действительно не стоят того, чтобы вносить возможные ошибки, позволяя пользователю установить начальные значения ваших локальных переменных , вызывая эту функцию с дополнительными параметрами.Это нарушает инкапсуляцию (вы можете сделать это правильно, но вы получите больше байтов, чем сэкономили, пропустив var).Кроме того, это действительно сбивает с толку любого, кто пытается прочитать ваш код.

0 голосов
/ 14 июня 2012

Кристиан Йохансен (Chistian Johansen) в статье «Разработка Javascript, управляемой тестами» (2011) утверждает: «В общем случае объект аргументов следует использовать только в том случае, если формальные параметры не могут решить проблему, потому что его использование сопряжено с ценой производительности.простая ссылка на объект вызовет некоторые издержки, указывая на то, что браузеры оптимизируют функции, которые его не используют. "

0 голосов
/ 07 декабря 2010

Те же преимущества, что и вы, можно получить, просто удалив ключевое слово var:

function howManyMatch(arr, pattern) {
  l = arr.length;
  total = 0;
  for (i = 0; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

Нет необходимости явно писать ключевое слово var, так как вы определяете все переменные в этом случае со значением (l = arr.length, total = 0, i = 0).

Кстати, обратите внимание, что вы не можете предопределять переменные, определяя их как аргументы функции. Это невозможно, например:

function howManyMatch(arr, pattern, i=0, l, total = 0){ ... }

Итак, я не думаю, что ваше решение для минимизации кода все-таки очень полезно, так как недостатки остаются;)


Редактировать

Я не думал о том, что определение переменных без ключевого слова var превратит их в глобальные переменные. Это может быть что-то, чего ты вообще не хочешь ...

Но когда я снова думаю о проблеме, я не понимаю, почему вы захотите определить переменные в аргументах функции. Все преимущества, которые вы предоставляете для этого метода, в основном верны и для этого примера:

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i=0;
  for (; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

А этот пример еще короче.

...