8

我最近遇到了这段 JavaScript 代码:

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

我很感兴趣,因为要编写这个测试,我会这样做:

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

这只是风格上的差异,还是其他代码的作者知道一些我不知道的优化?或者也许有不同的充分理由这样做,或者不使用正则表达式......?

在我看来,使用String.indexOf()for this 有点难以阅读(但是,我对正则表达式很满意),但是在某些情况下它可能比编写等效的正则表达式“更好”吗?

通过“更好”可能更快或更有效,(尽管显然这取决于浏览器的 JavaScript 引擎),或者我不知道的其他一些原因。任何人都可以启发我吗?

4

5 回答 5

11

我进行了一些测试。第一种方法稍微快一点,但即使在大量使用的情况下也不足以产生任何真正的影响......除非sCompOp可能是一个很长的字符串。因为第一种方法搜索的是一个固定长度的字符串,所以无论get多长时间它的执行时间都很稳定sCompOp,而第二种方法可能会遍历整个长度sCompOp

此外,第二种方法可能会匹配无效字符串-“blah blah blah <= blah blah”满足测试...

鉴于您可能正在其他地方解析运算符,我怀疑任何一种极端情况都会成为问题。但即使不是这种情况,对表达式进行小的修改也可以解决这两个问题:

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

测试代码:

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 中测试

于 2008-10-08T16:27:19.953 回答
3

我怀疑这是性能或优化的问题。我怀疑该代码的作者根本不熟悉或不熟悉正则表达式。还要注意逗号分隔的字符串是如何不分开以利用对象属性的——这也可能是对语言不熟悉的情况。

例如,在逗号分隔的允许运算符列表中测试运算符的另一种方法是拆分逗号分隔的允许运算符列表,并使用运算符作为属性对对象进行一次性初始化:

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

这个小的初始化开销可能会被快速查找的能力所抵消:

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

当然,这最终可能会整体变慢,但可以说是一种更清洁的方法。

于 2008-10-08T17:04:14.700 回答
2

曾经可能存在明显的速度差异,但现在不再如此。我认为这是:

  1. 来自 (godless) The Land Before REGEX 的遗留代码。
  2. 由不了解 REGEX 或害怕它的人撰写。
于 2008-10-08T16:12:06.413 回答
2

这让我想起了一些早期的基于 javascript 的getElementsByClassName实现。

indexOf比使用正则表达式快得多,但是使用的代码indexOf从假设开发人员将类名用空格(而不是制表符和换行符)分隔开来。公平地说,一些基于正则表达式的实现正在使用\b(单词边界),这与 CSS 规范不兼容(因为 CSS 允许在类名中使用连字符)。

在 IE 中使用indexOfto supportgetElementsByClassName确实会有所作为,因为没有更快的替代方案,并且 className 属性的底层 getter/setter 可以方便地用空格替换制表符和换行符。

于 2008-10-09T02:54:00.783 回答
1

它真的是一段古老的代码吗?它可能是在正则表达式广泛用于 javascript 之前编写的。总体而言,看起来有人试图过于聪明和“优化”该语句,或者来自 C 背景并且不习惯正则表达式。使用正则表达式可能很昂贵,但字符串连接也可能很昂贵,如果它不在循环中,我会选择更容易理解的那个(对我来说,正则表达式)。

于 2008-10-08T16:03:35.417 回答