Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >聊聊编码那些事,顺带实现base64

聊聊编码那些事,顺带实现base64

作者头像
Careteen
发布于 2022-02-14 08:33:12
发布于 2022-02-14 08:33:12
74800
代码可运行
举报
文章被收录于专栏:源码揭秘源码揭秘
运行总次数:0
代码可运行

目录

前言

日常工作中,频繁的使用base64取代小图标,以便减少HTTP请求进而达到性能优化的目的。基于此来聊聊编码的发展、为什么需要base64以及如何实现base64。此文章首发于聊聊编码那些事,顺带实现base64转载请注明来源。

进制间的转换

对任意进制的数进行任意进制转换

Number.prototype.toString(radix)

将任意进制数转换为十进制数

parseInt(string, radix)

几道关于parseInt的面试题

说到parseInt,不得不提到一个很有意思的面试题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 会输出什么?
[1, 2, 3].map(parseInt)
// => 1, NaN, NaN

map方法第一个参数为函数,函数有三个参数,array.map((item, index, array) => { ... })

实际上相当于

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function fn (item, index) {
  return parseInt(item, index)
}
[1, 2, 3].map(fn)
// parseInt迭代过程相当于如下
// parseInt(1, 0) => 1
// parseInt(2, 1) => NaN
// parseInt(3, 2) => NaN

再来看一个类似的面试题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 会输出什么?
'1 2 3'.replace(/\d/g, parseInt)
// => 1, NaN, 3

replace方法第二个参数若是一个函数,函数会有若干个参数。第一个为匹配模式的字符串;第二个为与模式中子表达式匹配的字符串,可以有零个或多个这样的参数。

实际上相当于如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function fn (...args) {
  // 只会取前两个参数
  return parseInt(args[0], args[1])
}
'1 2 3'.replace(/\d/g, fn)
// parseInt迭代过程相当于如下
// parseInt('1', 0) => 1
// parseInt('2', 2) => NaN
// parseInt('3', 4) => 3

其实在mdn中对parseInt/map/replace已经讲解的很详细,期望大家在工作之余不要太过浮躁,别做伸手党,静下心来啃一下文档并多做实践,很多面试题自然会迎刃而解。

编码发展历史

ASCII
GBK2312
GBK
GB18030/DBCS
Unicode
UTF-8

现在的标准,有如下特点

  • UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式
  • UTF-8就是每次以8个位为单位传输数据
  • 而UTF-16就是每次 16 个位
  • UTF-8 最大的一个特点,就是它是一种变长的编码方式
  • Unicode 一个中文字符占 2 个字节,而 UTF-8 一个中文字符占 3 个字节
  • UTF-8 是 Unicode 的实现方式之一

base64编码

为什么需要base64

在开发时,经常会有一些小图标图片,每一个图片都会有一次HTTP请求,由于浏览器对同一个域名的并发数量有限制,所以我们应该尽可能减少HTTP请求个数。

本文主要讲解编码相关,那就只讲解从编码入手如何去减少HTTP请求。

在计算机内部,任何信息最终都是使用一系列二进制存储,图片也不例外。

而且在img标签的src属性后跟上一个base64字符,如果该字符有效,那么会正常显示图片。

如何实现base64

以下涉及的所有代码均在仓库中,感兴趣的可以自取。

读取buffer转为json对象

首先准备一个2.txt文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
冯兰兰啊我说今晚月色这么美,你说是的。

case.js代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const fs = require('mz/fs')
const path = require('path')

// 读取成buffer对象
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... ] }

上面的依赖mz/fs已经将fs都包装成promise,所以我们能写的更像同步。

readFile函数如果第二个参数没有指定会读取成一个buffer流,是由一个个16进制数组合在一起的。

buffer.toJSON可以将一个buffer流转为一个json对象,十六进制也会被转十进制。如上输出所示。

将10进制转为2进制

十进制转为二进制可以通过Number.toString(2)方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 将10进制转为2进制
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'...]
将2进制拼一起3*8然后分隔成4*6

一个汉字在UTF-8规范中由三个字节组成,一个字节由8个二进制物理位构成。所以一个汉字实际占用内存3*8base64中我们实际需要6个物理位表示一个字节即2**6,所以做重新分割4*6

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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'...]
然后将2进制转成10进制

二进制转为十进制可以通过parseInt(string, 2)方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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码

base64中的64实际上是根据2**6所来,表示则由大写字母、小写字母、数字、+/构成。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const lowerCases = 'abcdefghijklmnopqrstuvwxyz'
const numbers = '0123456789'
const base64lib = `${lowerCases.toUpperCase()}${lowerCases}${numbers}+/`
console.log(base64lib)
// => ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
取到每一个base64码

然后我们则可以取到每一个base64

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

我们可以前往base64在线转码解码进行验证。

简化代码

对以上思路进行代码简化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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('冯')
console.log(fl) // => 5Yav

小结

如上我们可以实现将中文转为base64,同理我们也可以转换图片。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
async function read2JSON () {
  // let ret = await fs.readFile(path.resolve(__dirname, '2.txt'))
  // 读取图片
  let ret = await fs.readFile(path.resolve(__dirname, '../assets/encoding-base64-example.png'))
  console.log(ret.toJSON())
  return ret.toJSON()
}

特别的: 由于将2进制拼一起3*8然后分隔成4*6,原来存储一个汉字需要三个字节,现在需要四个字节存储,所以转换为base64后会比之前大3/1

下面笑脸图片则是由img的src属性展示的(github似乎将base64过滤了,并没有展示),不过本文并没有实现图片转base64,因为其逻辑较为复杂,但是本文讲解了大致思路,感兴趣的可再做深究。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
gulp 的运作方式分析
说到 gulp 的运作方式,就不得不提到 vinyl 和 Node.js 的 stream。
疯狂的技术宅
2020/12/31
4850
小程序云开发--云函数上传文件或图片 base64
但是我们同时也知道,云函数是后台服务端,具有管理员权限,只要能调用云函数上传文件就可以解决这个问题了
Kindear
2019/05/25
6.9K2
前端Base64编码知识,一文打尽
本文将详细的介绍前端 Base64 编码知识,探索起源,让大家对开发经常用到的 Base64 有个更全面深入的认知。
coder_koala
2021/08/26
1.3K0
为啥要 base64 编码?
在项目中,对报文进行压缩、加密后,最后一步一般是 base64 编码。因为 base64 编码的字符串更适合不同平台,不同语言的传输。
王小明_HIT
2021/05/20
1.8K0
一点知识丨Base64 的图片如何完美复制到系统粘贴板
最近开发过程中遇到了一个小知识点,这里有一张 Base64 编码的图片,我想要把它复制到系统的粘贴板中,这个该怎么解决?
崔庆才
2021/03/03
2.2K0
一点知识丨Base64 的图片如何完美复制到系统粘贴板
wasm不通过请求直接使用的方法
现将wasm二进制转为base64,方便代码引入;使用时再将其转为buffer数组。
治电小白菜
2024/07/19
2570
wasm不通过请求直接使用的方法
Plaid CTF Writeup [Treasure Map/CSS]
这两道题真是太有趣了!虽然标签是逆向,但是以前端为载体,有很多JS/CSS奇淫巧计,我已经迫不及待地想要和大家分享了。
戴兜
2023/04/27
1.5K0
Plaid CTF Writeup [Treasure Map/CSS]
Base64 原理
Base64 是什么?是将字节流转换成可打印字符、将可打印字符转换为字节流的一种算法。Base64 使用 64 个可打印字符来表示转换后的数据。
冬夜先生
2021/10/08
7800
面试官昨天问我对base64的理解,着实被问懵了
我们知道一个字节可表示的范围是 0 ~ 255(十六进制:0x00 ~ 0xFF), 其中 ASCII 值的范围为 0 ~ 127(十六进制:0x00 ~ 0x7F);而超过 ASCII 范围的 128~255(十六进制:0x80 ~ 0xFF)之间的值是不可见字符。
用户3806669
2021/03/25
4.6K0
面试官昨天问我对base64的理解,着实被问懵了
了不起的Base64
在我们项目开发中,Base64想必大家都不会很陌生,Base64是将「二进制数据」转换为文本的一种优雅方式,使存储和传输变得容易。但是,作为一个合格的程序员,我们应该有一种打破砂锅问到底的求助欲望。
前端柒八九
2023/11/08
5180
了不起的Base64
Dart 知识集锦 | Base64 编解码
在编程的世界中,数据的种类可谓是缤纷多彩。但是他们有本质的共性: 都是二进制的数据。在数据传输过程中,字节数组有时并不是很方便,比如网络传输。 Base64 包括小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"一共64个字符的字符集。它可以将 字节数组 进行编码进行传输。Dart 语言的 convert 包中,有 Base64Codec 支持 Base64 编解码,下面一起来看一下其使用方式:
张风捷特烈
2024/06/15
2750
Dart 知识集锦 |  Base64 编解码
blob和base64互转
交易场上的朋友胜过柜子里的钱款——托·富勒 blob转base64 // blob转base64 async function blobToBase64(blob) { let buffer = await blob.arrayBuffer() let bytes = new Uint8Array(buffer); console.log(bytes) // do anything with the byte array here let binary = '
阿超
2022/09/27
3780
一篇文章彻底弄懂Base64编码原理
----------------------------转载部分start-----------------------------
明明如月学长
2021/08/27
5.9K1
原生JS实现base64解码与编码
base64是用规定的64种字符来表示任意二进制数据的一种编码格式,而且这64种字符均是可见字符,而之所以要是可见的是因为在不同设备上处理不可见字符时可能发生错误。通常,电子邮件数据、公钥证书会经常使用。
IMWeb前端团队
2019/12/03
11.6K1
BASE64编码
附录:BASE64编码的原理(节选自http://www.vbzx.net/ArticleView/vbzx_Article_View_1199.asp)
源哥
2018/08/28
1.7K0
json.Marshal为什么会对[]byte类型进行base64编码处理?
在 json.Unmarshal时也有类似反向处理,src/encoding/json/decode.go[3]:
fliter
2024/02/05
4980
json.Marshal为什么会对[]byte类型进行base64编码处理?
前端 js base64解密
有勇气的牛排
2023/06/25
1.4K0
[APICloud实用教程]解决APICloud平台png照片转base64编码出错问题
在使用trans模块decodeImgToBase64函数时发现转换出来的编码上传的时候,无法正确显示。当我把转换出来的编码放在在线base64转照片的时候,提示编码错误,当我对比其他base64编码时发现trans模块decodeImgToBase64少了
小宋是呢
2019/06/27
1.1K0
Base64笔记
昨天的《MIME笔记》中提到,MIME主要使用两种编码转换方式----Quoted-printable和Base64----将8位的非英语字符转化为7位的ASCII字符。
ruanyf
2018/09/10
8830
Node.js中的Base64编码和解码
本文翻译自Base64 Encoding and Decoding in Node.js
ccf19881030
2020/10/28
18.7K0
相关推荐
gulp 的运作方式分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验