这是 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, ''); }
}