这是 2007 年的一篇老文:Faster JavaScript Trim.
测试页面:trim-test.html
感兴趣的几个方法:
function trim1(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } function trim2(str) { return str.replace(/^\s+/, '').replace(/\s+$/, ''); } function trim4(str) { return str.replace(/^\s+|\s+$/g, ''); } function trim8(str) { return str.replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1'); }
时至今日,有些结论已经发生变化:
1. trim1 中使用的正则优化:pre-check of required character and start of string anchor, 在最新的 JS 引擎中已经内置。trim4 也得到了非常好的优化,比 trim1, trim2 都快。
2. trim8 在 IE 中依旧非常有优势。这是因为 IE 对 \S\s (any character token) 有非常好的优化。另外 ?: (non-capturing group) 对性能也有提升。
3. trim10 是非正则实现方案,速度飕飕的。原文中指出关键点:正则在处理过程中无法直接跳转到字符串末尾,从而导致在处理长字符串时耗时稍长。于是有了混合版本 trim11 和 trim11 的改进版本 trim12:
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; } function trim12(str) { str = str.replace(/^\s\s*/, ""); var ws = /\s/, i = str.length; while (ws.test(str.charAt(--i))) {} return str.slice(0, i + 1); }
4. 在原文的回复中,还有利用空间换时间的 map 方案。
5. 对于普通应用,比如 JS 框架,原文作者推荐使用 trim1. 从上面的变化可以看出,目前更好的方案是 trim4. 这也正是当今流行 JS 框架中广泛采用的实现方案。对于特殊应用需要处理长字符串时,推荐采用 trim11.
6. 目前 Firefox 3 和 Chrome 4 中都已原生实现 String.prototype.trim, 对于这些浏览器,原生实现始终是最佳方案。
7. 原文作者的 final note 值得注意:许多开发者习惯用变量缓存正则,这可以避免正则的重复编译,但这对于简单如 trim 的正则来说意义不大。trim 的正则如此简单,编译时间是纳秒级的。而且不少浏览器自身已对最近使用的正则进行缓存,不会存在重复编译的问题。trim13 用来验证此观点,除了 IE, 其它浏览器下,当重复次数 times 变大时,trim13 反而比 trim12 略有优势。
8. 讨论一个有争议的点:对于 JS 类库来说,trim 方法究竟应不应该附加在 String.prototype 上呢?侵入 built-in 对象,会导致for...in
产生某些非预期结果。但是,对于 String 来说,用for...in
遍历 String 本就是非常不明智的行为。为了这些“愚蠢的”使用方法,而坚决不侵入 built-in 对象,是否真的值得?毕竟从用户角度讲,str.trim()
,比类似$.trim(str)
这种写法自然多了。
最后给一个我的方案:
if(!String.prototype.trim) { var TRIM_REG = /^\s+|\s+$/g; String.prototype.trim = function() { return this.replace(TRIM_REG, ''); } }