読者です 読者をやめる 読者になる 読者になる

文字列連結を素早くするオブジェクト

JavaScriptの文字列連結はすればするほど長くなればなるほど重くなるっていうのは有名な話でどうしても何回も連結せざるを得ない状況(テンプレート処理)では以下のような俺オブジェクトを使って対処してきました。
ただ人間欲が出てくると replace したいとか length 取得したいよ...と思い、自分で実装する必要が出ていました。ただ String.prototype が継承できるのを思い出し作り直したのが以下のもの。

function Buffer()
{
    var k = -1, b = [];

    this.append = function()
    {
        for(var i=0,f=arguments.length;i<f;i++)
        {
            if(!arguments[i]){ return; };
            b[++k] = arguments[i];
        };
    };

    function toString(s){ return b.join(s || ''); };
    this.valueOf = this.toString = toString;
};
//今回は以下の1行追加
Buffer.prototype = new String();

これを利用すると何が嬉しいのかというと

  • string += string を連呼するよりもappendを連呼したほうが連結は早くなる。
  • 普通のStringのメソッドが呼べる。つまり、charAt呼びだせたり、replaceできるぜ!みたいな具合です。
buffer = new Buffer();
buffer.append('foo','bar');

alert(buffer.length); // 3 + 3 = 6
alert(buffer.replace('foo','bar')); // bar bar
alert(buffer); // foobar
alert(buffer.toString(",")); // foo,bar

ベンチマーク*1

Bufferのみ*2 Buffer.prototype付 string += string
平均 318.2 320.2 1409.1
標準偏差 11.7 11.9 43.2
for(i=0;i<10000;i++){
    b.append('abcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEF');
}
b = '';
c = 'abcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEFabcdefABCDEF';
for(i=0;i<10000;i++){
    b += c;
}

ご自由にどうぞ

*1:10回ずつfxで検証

*2:prototype = new String()無