前不久blog频道有人发表了一篇讲js里各种trim实现的 http://justjavac.iteye.com/blog/933093
不过没有提及Dojo中的trim。Dojo中有两种trim实现:
1.较为常用的:
dojo.trim = String.prototype.trim ?
function(str){ return str.trim(); } :
function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
2.速度最快但是实现较为复杂:
dojo.string.trim = String.prototype.trim ?
dojo.trim : // aliasing to the native function
function(str){
str = str.replace(/^\s+/, '');
for(var i = str.length - 1; i >= 0; i--){
if(/\S/.test(str.charAt(i))){
str = str.substring(0, i + 1);
break;
}
}
return str;
};
第一种实现位于dojo base中,是dojo针对JS缺陷做出的一种弥补,也是dojo里最经常被调用到的trim。
第二种实现位于dojo.string中,是dojo里string工具类的方法。这种实现比较诡异,也很有趣。
另外在Dojo注释里看到有关各种trim方法的对比的文章,故将其翻译下来,原文地址:Faster Javascript Trim
Faster JavaScript Trim
js中并没有自带trim方法,但是该方法被无数的JS库实现了,并且通常都是将trim置为全局函数、或者将trim作为String.prototype
的方法。然而,我从没见到过一种
trim实现能够充分发挥出它的效率,毕竟,大多数的程序员并不了解正则表达式的性能问题(我就是= =!)。
当看到那些极为糟糕的trim实现之后,我决定研究一下如何编写出高效率的trim。在正式进入分析之前,先来看一下结论:
Method |
Fifox2 |
IE6 |
trim1 |
15ms |
<0.5ms |
trim2 |
31ms
|
<0.5ms |
trim3 |
46ms |
31ms |
trim4 |
47ms |
46ms |
trim5 |
156ms |
1656ms |
trim6 |
172ms |
2406ms |
trim7 |
172ms |
1640ms |
trim8 |
281ms |
<0.5ms |
trim9 |
125ms |
78ms |
trim10 |
<0.5ms |
<0.5ms |
trim11 |
<0.5ms |
<0.5ms |
Note1:
这里的比较结果是在作者的电脑上对Magna Carta
(over 27,600 characters)
运行20次trim之后得出的
Note2:
trim4和trim6是JS库中最经常使用的实现方式
Note3:
前文说的极为糟糕的trim实现并不在上面11种trim里,但在文章的末尾会提到。
The analysis
JS里的trim可能有很多种实现方式,上表的11种是最显著的。这里所作的分析都是基于FF2.0.0.4和IE6。(太老了,不过在天朝,研究IE6还是有意义的)
Trim1:
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
如果考虑各种情形,这也许就是最好的一种trim实现了。trim1在处理长字符串时速度优势非常显著。速度在很大程度上取决于这里的两个regexp触发的js正则引擎优化。
Trim2:
return str.replace(/^\s+/, '').replace(/\s+$/, '');
非常类似于trim1,但是速度稍慢,因为它不会触发一些优化。
Trim3:
return str.substring(Math.max(str.search(/\S/), 0), str.search(/\S\s*$/) + 1);
trim3通常比下面的trim快,但是比trim1和trim2慢。(Its speed comes from its use of simple, character-index lookups.不懂...)
Trim4:
return str.replace(/^\s+|\s+$/g, '');
这是一种较为简单的实现,因而被广泛用在各种js库里。如果作用于短字符串,而且没有头部空白或者尾部,trim4会是最快的。 这种速度上的优势部分来自于它触发了initial-character discrimination optimization
。如果是作用于长字符串,那么它比trim1-3慢,因为最高级别的‘alternation ’(即该regexp里有个或)阻碍了一些优化。
Trim5:
str = str.match(/\S+(?:\s+\S+)*/);
return str ? str[0] : '';
如果是作用在空字符串或者仅仅包含空格(“whitespace-only”) 的字符串上,trim5的速度可能会最快,因为它会触发一些pre-check of required character
的优化。注意,在IE6下该方法针对长字符串会非常的慢。
Trim6:
return str.replace(/^\s*(\S*(\s+\S+)*)\s*$/, '$1');
这也是一种比较普遍的做法,被一些牛逼的js code所推广。它和trim8很相似,但没有好的理由去用它,特别是它在IE6下会非常的慢。
Trim7:
return str.replace(/^\s*(\S*(?:\s+\S+)*)\s*$/, '$1');
和trim6基本相同,唯一的区别就是trim7用了一个非捕获性分组(IE5.0及以下不支持)。同样,在IE6下会非常慢。
Trim8:
return str.replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
trim8使用了简单、一趟(因为用了?)、贪婪的匹配方式。trim8在IE6下会特别特别快。说明IE会针对 "any character" tokens做一些超级优化。
Trim9:
return str.replace(/^\s*([\S\s]*?)\s*$/, '$1');
如果作用于非常短的字符串,而且字符串包含非空格字符以及边缘是空格,那么trim9将会非常快。这种性能上的优势是由于它使用了简单的、一趟、惰性贪婪匹配。同trim8,trim9在IE6下速度也远快于FF。
下面我在一个JS库里的实现看到的trim实现,列出来做一个警示
:
return str.replace(/^\s*([\S\s]*)\b\s*$/, '$1');
该方法有时是最快的,比如是作用在短字符串,而且该字符串包含非空格字符以及边缘是空格。但如果是长字符串,里头有很多单词的边界,它的性能就很差了。如果是仅仅由空白字符组成的长字符串,它的性能将无比糟糕(since that triggers an exponentially increasing amount of backtracking)。不要使用这种实现!
A different endgame
上面表格中的11种trim尚有2种还没涉及。这2种方法采用的是非正则表达式、正则与非正则混合的方法。
经过比较和分析后,我想尝试一下如何用非正则表达式去实现一个trim:
Trim10:
function trim10 (str) {
var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
for (var i = 0; i < str.length; i++) {
if (whitespace.indexOf(str.charAt(i)) === -1) {
str = str.substring(i);
break;
}
}
for (i = str.length - 1; i >= 0; i--) {
if (whitespace.indexOf(str.charAt(i)) === -1) {
str = str.substring(0, i + 1);
break;
}
}
return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}
它的表现如何呢?如果是针对长字符串,并且头部尾部不包含过多的空白,该方法会轻松的战胜上述的9种trim(除了IE中的trim1/2/8,它们快的太离谱了)
这是否意味着FF里的正则表达式很慢?一点也不。这里的问题在于,尽管正则表达式非常适用于去除头部的正则表达式,但是它们并没有一个合适的方式去跳转到字符串的末尾。然而trim10却可以做到,它的第二个for循环直接从字符串的末尾开始处理。
知道了这点,那么不如去创造一种正则和非正则的混合实现,它既有正则表达式在处理字符串开头空白的性能,又有非正则表达式在处理字符串末尾空白的速度优势。
Trim11:
function trim11 (str) {
str = str.replace(/^\s+/, '');
for (var i = str.length - 1; i >= 0; i--) {
if (/\S/.test(str.charAt(i))) {
str = str.substring(0, i + 1);
break;
}
}
return str;
}
虽然trim11在处理有些字符串的时候比trim10慢,但是它任然速度飞快,并且使用了更少的代码。而且,如果处理的字符串在开头有大量的空白(包含直接由空白组成的字符串),那么trim11的速度将会明显比trim10快。
In conclusion…
由于不同浏览器的区别,处理的也是不同类型的字符串,因此没有一种trim方法总是表现的比其他所有都快。这里我有一个一般的建议:
- 使用trim1
如果你想获得一个比较快的速度,并且能跨浏览器使用
- 使用trim11
如果你想在不同的浏览器中快速的处理长字符串
如果你想自己测测上述所有trim方法的性能,那么尽量按照我的适用建议。后台处理可能使得某一次的测试结果极为不准确,因此建议测试很多次,并且仅仅取跑的最快的一些结果。
最后一点建议,虽然很多人喜欢缓存正则表达式,比如将它们作为全局变量存储起来,这样以后就不要重复编译了。但是这对trim方法来说意义不大。另外一些浏览器会自动的缓存正则表达式,所以在一些不包含其它regexp的循环里使用trim,浏览器实际上并不会去重复的编译。
better trim
写完这些不久我就意识到trim10/11可以被更好的改写。trim12采用了和trim11类似的正则非正则混合的方式。
Trim12:
function trim12 (str) {
var str = str.replace(/^\s\s*/, ''),
ws = /\s/,
i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
}
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
去蝴蝶书上查了下,Javascript中的“ \s ”相当于“ [ \f \n \r \t \u000B \u0020 \u00A0 \u2028 \u2029 ] ”
其中:
\f 换页符
\n 换行符
\r 回车符
\t tab符
\u000B 垂直定位符
\u0020 空格
\u00A0 非中断空格
\u2028 行分隔符
\u2029 段落分隔符
根据Ecma-262 3rd 中描述:

分享到:
相关推荐
"JavaScript"是关键,这意味着内容专注于JavaScript,这是一种广泛用于Web开发的脚本语言,用于实现客户端交互、网页动态效果以及数据处理等。 **文件名列表:** 由于只给出"javascript"作为文件名,我们推测这...
MooTools是一个强大的JavaScript库,它提供了一系列工具和方法,帮助开发者更高效地编写和组织JavaScript代码。...虽然文档为英文,但通过翻译工具或自行学习,可以有效地掌握这个强大的JavaScript库。
总的来说,jQuery中文手册是开发者不可或缺的资源,它详细解读了jQuery的各个方面,帮助开发者高效地编写JavaScript代码,实现更丰富的网页交互。无论是初学者还是经验丰富的开发者,都可以从中受益。
《jQuery中文文档1.8和1.4的chm文档》是两个版本的jQuery官方文档的中文翻译版,主要用于帮助开发者理解和使用这个广泛应用于Web开发的JavaScript库。jQuery以其简洁的API和强大的功能,极大地简化了DOM操作、事件...
6. JavaScript 注释:在JavaScript中,可以使用//添加单行注释,或者使用/*...*/添加多行注释。 7. 内存和外存:内存(RAM)相对于外存(如硬盘)来说,具有更高的访问速度,但容量较小且成本较高。因此,描述是...
**翻译**: Apache Tomcat 是官方 Java Servlet 和 JavaServer Pages 技术参考实现中使用的 Servlet 容器。Java Servlet 和 JavaServer Pages 规范是由 Sun 在 Java 社区过程中开发的。Apache Tomcat 是在一个开放和...