Pack and unpack bytes to strings
function pack(bytes) {
    var str = "";
// You could make it faster by reading bytes.length once.
    for(var i = 0; i &lt; bytes.length; i += 2) {
// If you're using signed bytes, you probably need to mask here.
        var char = bytes[i] &lt;&lt; 8;
// (undefined | 0) === 0 so you can save a test here by doing
//     var char = (bytes[i] &lt;&lt; 8) | (bytes[i + 1] &amp; 0xff);
        if (bytes[i + 1])
            char |= bytes[i + 1];
// Instead of using string += you could push char onto an array
// and take advantage of the fact that String.fromCharCode can
// take any number of arguments to do
//     String.fromCharCode.apply(null, chars);
        str += String.fromCharCode(char);
    }
    return str;
}

function unpack(str) {
    var bytes = [];
    for(var i = 0; i &lt; str.length; i++) {
        var char = str.charCodeAt(i);
// You can combine both these calls into one,
//    bytes.push(char &gt;&gt;&gt; 8, char &amp; 0xff);
        bytes.push(char &gt;&gt;&gt; 8);
        bytes.push(char &amp; 0xFF);
    }
    return bytes;
}


so to put it all together

function pack(bytes) {
    var chars = [];
    for(var i = 0, n = bytes.length; i &lt; n;) {
        chars.push(((bytes[i++] &amp; 0xff) &lt;&lt; 8) | (bytes[i++] &amp; 0xff));
    }
    return String.fromCharCode.apply(null, chars);
}

function unpack(str) {
    var bytes = [];
    for(var i = 0, n = str.length; i &lt; n; i++) {
        var char = str.charCodeAt(i);
        bytes.push(char &gt;&gt;&gt; 8, char &amp; 0xFF);
    }
    return bytes;
}