Стиль / оптимизация JavaScript: String.indexOf () v. Regex.test () - PullRequest
9 голосов
/ 08 октября 2008

Я недавно натолкнулся на этот фрагмент кода JavaScript:

if (",>=,<=,<>,".indexOf("," + sCompOp + ",") != -1)

Я был заинтригован, потому что написать этот тест я бы сделал:

if (/(>=|<=|<>)/.test(sCompOp))

Это просто стилистическая разница, или автор другого кода знает что-то об оптимизации, чего я не знаю? Или, может быть, есть другая веская причина для этого или не использовать регулярные выражения ...?

Мне кажется, что использовать String.indexOf() для этого немного сложнее для чтения (но тогда я вполне знаком с регулярными выражениями), но есть ли случаи, когда это может быть "лучше", чем писать эквивалент регулярное выражение?

«Лучше» - это может быть быстрее или эффективнее (хотя, очевидно, это зависит от механизма JavaScript браузера) или по какой-то другой причине, о которой я не знаю. Может ли кто-нибудь просветить меня?

Ответы [ 5 ]

10 голосов
/ 08 октября 2008

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

Кроме того, второй метод будет потенциально соответствовать недопустимым строкам - "бла-бла-бла <= бла-бла" удовлетворяет критерию ... </p>

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

/^(>=|<=|<>)$/

Код тестирования:

function Time(fn, iter)
{
   var start = new Date();
   for (var i=0; i<iter; ++i)
      fn();
   var end = new Date();
   console.log(fn.toString().replace(/[\r|\n]/g, ' '), "\n : " + (end-start));
}

function IndexMethod(op)
{
   return (",>=,<=,<>,".indexOf("," + op + ",") != -1);
}

function RegexMethod(op)
{
   return /(>=|<=|<>)/.test(op);
}

function timeTests()
{
   var loopCount = 50000;

   Time(function(){IndexMethod(">=");}, loopCount);
   Time(function(){IndexMethod("<=");}, loopCount);
   Time(function(){IndexMethod("<>");}, loopCount);
   Time(function(){IndexMethod("!!");}, loopCount);
   Time(function(){IndexMethod("the quick brown foxes jumped over the lazy dogs");}, loopCount);
   Time(function(){IndexMethod("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");}, loopCount);

   Time(function(){RegexMethod(">=");}, loopCount);
   Time(function(){RegexMethod("<=");}, loopCount);
   Time(function(){RegexMethod("<>");}, loopCount);
   Time(function(){RegexMethod("!!");}, loopCount);
   Time(function(){RegexMethod("the quick brown foxes jumped over the lazy dogs");}, loopCount);
   Time(function(){RegexMethod("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");}, loopCount);
}

timeTests();

Протестировано в IE6, FF3, Chrome 0.2.149.30

2 голосов
/ 09 октября 2008

Это напоминает мне о некоторых ранних реализациях getElementsByClassName на основе javascript.

indexOf был намного быстрее, чем использование регулярного выражения, но код, который использовал indexOf, начинался с предположения, что разработчик будет разделять имена классов пробелами (а не табуляторами и переводами строк). Справедливости ради следует отметить, что некоторые реализации на основе регулярных выражений использовали \ b (границу слова), что несовместимо со спецификацией CSS (поскольку CSS допускает дефисы в именах классов).

Использование indexOf для поддержки getElementsByClassName в IE может реально изменить ситуацию, поскольку нет более быстрых альтернатив, а базовый метод получения / установки свойства className удобно заменяет табуляции и переводы строк пробелами.

1 голос
/ 08 октября 2008

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

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

var aOps = ">=,<=,<>".split(",");
var allowableOps = {};
for (var iLoop = 0; iLoop < aOps.length; iLoop++) {
  allowableOps[aOps[iLoop]] = true;
} //for

Эти небольшие издержки инициализации, вероятно, будут компенсированы возможностью быстрого поиска:

if (allowableOps[sCompOp]) { ... }

Конечно, в целом это может быть медленнее, но, возможно, это более чистый подход.

1 голос
/ 08 октября 2008

Возможно, когда-то была заметная разница в скорости, но это уже не так. Я думаю, что это либо:

  1. Наследственный код от (безбожной) Земли до REGEX.
  2. Написано кем-то, кто не знает о REGEX или боится его.
1 голос
/ 08 октября 2008

Это действительно старый кусок кода? Возможно, он был написан до того, как регулярные выражения стали широко использоваться в javascript. В целом, похоже, что кто-то пытался быть слишком умным и «оптимизировал» это утверждение или исходил из опыта Си и не использовался для регулярных выражений. Регулярное выражение может быть дорогим в использовании, но конкатенация строк может быть слишком сложной, и если бы она не была в цикле, я бы выбрал тот, который легче понять (для меня это регулярное выражение).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...