Base64 encoding and decoding in client-side Javascript

前端 未结 14 2066
挽巷
挽巷 2020-11-22 04:27

Are there any methods in JavaScript that could be used to encode and decode a string using base64 encoding?

14条回答
  •  情深已故
    2020-11-22 05:05

    Did someone say code golf? =)

    The following is my attempt at improving my handicap while catching up with the times. Supplied for your convenience.

    function decode_base64(s) {
      var b=l=0, r='',
      m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      s.split('').forEach(function (v) {
        b=(b<<6)+m.indexOf(v); l+=6;
        if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
      });
      return r;
    }
    

    What I was actually after was an asynchronous implementation and to my surprise it turns out forEach as opposed to JQuery's $([]).each method implementation is very much synchronous.

    If you also had such crazy notions in mind a 0 delay window.setTimeout will run the base64 decode asynchronously and execute the callback function with the result when done.

    function decode_base64_async(s, cb) {
      setTimeout(function () { cb(decode_base64(s)); }, 0);
    }
    

    @Toothbrush suggested "index a string like an array", and get rid of the split. This routine seems really odd and not sure how compatible it will be, but it does hit another birdie so lets have it.

    function decode_base64(s) {
      var b=l=0, r='',
      m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      [].forEach.call(s, function (v) {
        b=(b<<6)+m.indexOf(v); l+=6;
        if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
      });
      return r;
    }
    

    While trying to find more information on JavaScript string as array I stumbled on this pro tip using a /./g regex to step through a string. This reduces the code size even more by replacing the string in place and eliminating the need of keeping a return variable.

    function decode_base64(s) {
      var b=l=0,
      m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      return s.replace(/./g, function (v) {
        b=(b<<6)+m.indexOf(v); l+=6;
        return l<8?'':String.fromCharCode((b>>>(l-=8))&0xff);
      });
    }
    

    If however you were looking for something a little more traditional perhaps the following is more to your taste.

    function decode_base64(s) {
      var b=l=0, r='', s=s.split(''), i,
      m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      for (i in s) {
        b=(b<<6)+m.indexOf(s[i]); l+=6;
        if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
      }
      return r;
    }
    

    I didn't have the trailing null issue so this was removed to remain under par but it should easily be resolved with a trim() or a trimRight() if you'd prefer, should this pose a problem for you.

    ie.

    return r.trimRight();
    

    Note:

    The result is an ascii byte string, if you need unicode the easiest is to escape the byte string which can then be decoded with decodeURIComponent to produce the unicode string.

    function decode_base64_usc(s) {      
      return decodeURIComponent(escape(decode_base64(s)));
    }
    

    Since escape is being deprecated we could change our function to support unicode directly without the need for escape or String.fromCharCode we can produce a % escaped string ready for URI decoding.

    function decode_base64(s) {
      var b=l=0,
      m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      return decodeURIComponent(s.replace(/./g, function (v) {
        b=(b<<6)+m.indexOf(v); l+=6;
        return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
      }));
    }
    

    nJoy!

提交回复
热议问题