Talk about coding things, and by the way, implement base64

Catalog

Preface

In daily work, Base64 is frequently used to replace small icons in order to reduce HTTP requests and achieve performance optimization. Based on this, we will talk about the development of encoding, why Base64 is needed and how to implement base64. This article was first published in Talk about coding things, and by the way, implement base64 Please indicate the source for reprinting.

Conversion between binaries

Some pre-knowledge also involves some classical interview questions.

Arbitrary Binary Conversion of Arbitrary Binary Numbers

Number.prototype.toString(radix)

Converting Arbitrary Number to Decimal Number

parseInt(string, radix)

Several Interview Questions on parseInt

Speaking of parseInt, I have to mention an interesting interview question.

// What will it output?
[1, 2, 3].map(parseInt)
// => 1, NaN, NaN

The first parameter of the map method is a function, which has three parameters, array. map ((item, index, array) => {...})

Actually equivalent to

function fn (item, index) {
  return parseInt(item, index)
}
[1, 2, 3].map(fn)
// The parseInt iteration process is equivalent to the following
// parseInt(1, 0) => 1
// parseInt(2, 1) => NaN
// parseInt(3, 2) => NaN

Let's look at a similar interview question.

// What will it output?
'1 2 3'.replace(/\d/g, parseInt)
// => 1, NaN, 3

If the second parameter of the replace method is a function, the function will have several parameters. The first is a string matching a pattern; the second is a string matching a pattern neutron expression, with zero or more such parameters.

In fact, it is equivalent to the following

function fn (...args) {
  // Only the first two parameters will be taken.
  return parseInt(args[0], args[1])
}
'1 2 3'.replace(/\d/g, fn)
// The parseInt iteration process is equivalent to the following
// parseInt('1', 0) => 1
// parseInt('2', 2) => NaN
// parseInt('3', 4) => 3

In fact, parseInt/map/replace has been explained in detail in mdn. I hope you don't be too impetuous, don't be an outspoken party, calm down to chew the documents and do more practice, many interview questions will naturally be solved.

Coding History

ASCII

GBK2312

GBK

GB18030/DBCS

Unicode

UTF-8

The current standards have the following characteristics

  • UTF-8 is the most widely used way to implement Unicode on the Internet.
  • UTF-8 transmits data in eight units at a time.
  • UTF-16 is 16 bits at a time.
  • One of the biggest features of UTF-8 is that it is a variable-length encoding method.
  • Unicode takes up 2 bytes for a Chinese character, UTF-8 takes up 3 bytes for a Chinese character.
  • UTF-8 is one of the ways to implement Unicode

base64 encoding

Why base64 is needed

In development, there are often some small icon pictures, each picture will have an HTTP request, because the browser has a limited number of concurrent domain names, so we should try to reduce the number of HTTP requests.

This article mainly talks about coding, so it only talks about how to reduce HTTP requests from coding.

Within a computer, any information is ultimately stored in a series of binaries, and pictures are no exception.

And the src attribute of the img tag is followed by a base64 character. If the character is valid, the picture will be displayed normally.

How to Realize base64

All the code involved below is in Warehouse Interest can be self-selected.

Read buffer to json object

First, prepare a 2.txt file.

Feng Lanlan, I said the moonlight was so beautiful tonight, you said yes.

case.js code

const fs = require('mz/fs')
const path = require('path')

// Read as a buffer object
async function read2JSON () {
   let ret = await fs.readFile(path.resolve(__dirname, '2.txt'))
   console.log(ret.toJSON())
   return ret.toJSON()
}
read2JSON()
// => { type: 'Buffer', data: [ 229, 134, 175, 229... ] }

The above dependencies mz/fs fs have been packaged as promise, so we can write more like synchronization.

The readFile function reads into a buffer stream if the second parameter is not specified and is composed of hexadecimal numbers.

buffer.toJSON You can convert a buffer stream to a json object, and hexadecimal is also converted to decimal. As shown in the output above.

Convert decimal to binary

Converting decimal to binary can be done by Number.toString(2) method

// Convert decimal to binary
async function data2b () {
  let data = await read2JSON()
  let ret = []
  data.data.forEach(item => {
    ret.push(item.toString(2))
  })
  console.log(ret)
  return ret
}
data2b()
// => [ '11100101', '10000110', '10101111', '11100101'...]

Put the binary together by 3*8 and then divide it into 4*6

A Chinese character is composed of three bytes in UTF-8 specification, and one byte is composed of eight binary physical bits. So a Chinese character actually occupies 3*8 memory. In base64, we need 6 physical bits to represent a byte, that is, 2** 6, so we need to re-divide 4*6.

async function split () {
  let data = await data2b()
  let dataStr = data.join('')
  let ret = []

  let splitUnit = 6
  let flag = 0
  while (flag < dataStr.length) {
    ret.push(dataStr.substr(flag, splitUnit))
    flag = flag + splitUnit
  }
  console.log(ret)
  return ret
}
split()
// => [ '111001', '011000', '011010', '101111'...]

Then convert the binary system to the decimal system

Binary to decimal can be converted by parseInt(string, 2) method

async function data20 () {
  let data = await split()
  let ret = data.map(item => {
    return parseInt(item, 2)
  })
  console.log(ret)
  return ret
}
data20()
// => [ 57, 24, 26, 47, 57, 24, 22, 48, 57, 24, 22, 48 ]

base64 code

64 in base64 is actually based on 2** 6, which is composed of capital letters, lowercase letters, numbers, +/

const lowerCases = 'abcdefghijklmnopqrstuvwxyz'
const numbers = '0123456789'
const base64lib = `${lowerCases.toUpperCase()}${lowerCases}${numbers}+/`
console.log(base64lib)
// => ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Get each base64 code

Then we can get each base64 code.

async function main () {
  let data = await data20()
  let ret = []
  data.forEach(item => {
    ret.push(base64lib[item])
  })
  console.log(ret.join(''))
  return ret.join()
}

main()
// => 5Yav5YWw5YWw5ZWK5oiR6K+05LuK5pma5pyI6Imy6L+Z5LmI576O77yM5L2g6K+05piv55qE44CC

We can go there. base64 Online Transcoding and Decoding Verify.

Simplified code

Code simplification for the above ideas

const CHARTS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function transfer (str) {
  let buf = Buffer.from(str)
  let result = ''
  for(let b of buf){
    result += b.toString(2)
  }
  return result.match(/(\d{6})/g).map(val => parseInt(val, 2)).map(val => CHARTS[val]).join('')
}
let fl = transfer('Feng')
console.log(fl) // => 5Yav

Summary

If we can convert Chinese to base64, we can also convert pictures.

async function read2JSON () {
  // let ret = await fs.readFile(path.resolve(__dirname, '2.txt'))
  // Read pictures
  let ret = await fs.readFile(path.resolve(__dirname, '../assets/encoding-base64-example.png'))
  console.log(ret.toJSON())
  return ret.toJSON()
}

Special: Because Put the binary together by 3*8 and then divide it into 4*6 It used to take three bytes to store a Chinese character, but now it needs four bytes to store it, so it will be 3/1 larger than before when converted to base64.

The following pictures of smiling faces are displayed by the src attribute of img, but this article does not realize the conversion of pictures to base64, because its logic is more complex, but this article explains the general idea, which can be further studied.

Keywords: Javascript encoding JSON Attribute ascii

Added by sherry on Fri, 06 Sep 2019 11:45:14 +0300