正则表达式在使用中分好几个阶段,理解这些阶段对于代码优化大有裨益。其中最主要的2个阶段是"编译"和"执行"。 编译发生在表达式第一次创建的时候,执行则发生在匹配的时候。
编译时js引擎会把表达式解析成内部表达形式,通常浏览器会有自己的优化机制,会把之前编译好的缓存起来,如果2个表达式一样就用之前那个。 当然,作为一名忍者,我们不能认为所有浏览器都有这种优化。对于复杂的正则表达式,通过预编译我们能观察到明显的性能提升。
在7.2中我们知道有2种预编译方法,并介绍了2者的区别。下面我们来看一个具体例子,进一步说明构造器方法的优越性。 这个例子的功能是判断一个dom是否还有指定的classname。classname是动态指定的。
Listing 7.3 Compiling a runtime regular expression for later use
<div class="samurai ninja"></div> <!--#1-->
<div class="ninja samurai"></div> <!--#1-->
<div></div> <!--#1-->
<span class="samurai ninja ronin"></span> <!--#1-->
<script>
function findClassInElements(className, type) {
var elems = //#2
document.getElementsByTagName(type || "*");
var regex = //#3
new RegExp("(^|\\s)" + className + "(\\s|$)");
var results = []; //#4
for (var i = 0, length = elems.length; i < length; i++)
if (regex.test(elems[i].className)) { //#5
results.push(elems[i]);
}
return results;
}
assert(findClassInElements("ninja", "div").length == 2,
"The right amount fo div ninjas was found.");
assert(findClassInElements("ninja", "span").length == 1,
"The right amount of span ninjas was found.");
assert(findClassInElements("ninja").length == 3,
"The right amount of ninjas was found.");
</script>
这段代码首先声明了几个元素供测试,然后定义了一个函数,用来寻找dom中是否含有指定的className
因为className是动态指定的,所以只能使用new RegExp
构造。
listing7.3中正则的含义是:匹配开头,或者空格后紧跟着className
,然后跟着空格或者结尾的模式。注意在字符串中我们必须用
\\
表示一个反斜杠。最好把“或”的前后部分括起来,这是个好习惯。之前讲过,括号具有双重含义,下面我们就来讲讲“捕获”
findClassInElements函数没有对未定义的className进行判断,如果不指定,className就变成"undefined"字符串,会匹配
class=undefined
的类。所以在用字符串构造正则的时候,这一点需要谨慎。