JavaScript стиль / оптимизация: строка.indexOf () V. Regex.тест()

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

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

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

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

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

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

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

5 ответов


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

кроме того, второй метод потенциально будет соответствовать недопустимому строки - "бла бла бла

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

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

Тестирование кода:

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


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

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

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


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


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

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

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

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

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

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

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

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