在node环境中require了一个module1.js做了哪些事



先看一个熟悉的例子

1
2
3
node-source-code
- index.js
- module1.js

module1.js

1
module.exports.content = 'hello hardy'

index.js

1
2
const module1 = require('./module1')
console.log(module1.content) // hello hardy

why?why console hello hardy

首先要分析一下node代码的执行过程

  • 1、默认调用require方法
  • 2、模块的原型上有require方法(Module.prototype.require)
  • 3、调用模块的加载方法(Module._load), 返回module.exports
  • 4、解析文件名(Module._resolveFilename), 找到文件的绝对路径并按顺序尝试添加后缀(.js, .json, .node)
  • 5、默认查找是否曾缓存过(Module._cache)
  • 6、创建模块(new Module), constructor(id, exports)
  • 7、缓存模块
  • 8、尝试加载模块
  • 9、第三方模块查找路径(module.paths)
  • 10、获取模块扩展名,根据扩展名调用对应的方法(Module._extensions, 策略模式)
  • 11、fs读取文件内容(utf8)
  • 12、编译(module._compile)
  • 13、讲用户的内容包裹到一个函数中(function(exports, require, module, filename, dirname) {})

    最终返回module.exports, 用户会给module.exports赋值

它在这里: https://github.com/HHardyy/node-source-code

进制转换

常用的进制
  • 10进制
  • 2进制(0b11)
  • 8进制(0o66)
  • 16进制(0x16)
进制的互相转化
  • 一个字节以8个bit位,编码过程以字节为单位,常见一个字节组成一个字符, 双(三)字节组成一个汉字
  • 1、把任意进制转换成10进制,需要用当前位所在的值 * 当前进制^第几位
- - - - - - - -
1 1 1 1 1 1 1 1
1x2^7 1x2^6 1x2^5 1x2^4 1x2^3 1x2^2 1x2^1 1x2^0

一个字节代表10进制的话就是255

1
2
3
4
5
let sum = 0
for (let i = 0; i <= 7; i++) {
sum+=2**i
}
console.log(sum) // 255

255再转成16进制

1
2
console.log(Math.floor(255 % 16));  // 15
console.log('0123456789abcdefghijklmn'.charAt(15)); // f

所以16进制最大的字节就是0xff

255再转成8进制

1
console.log(255 % 8);  // 7

所以10进制转换成任意进制都可以采用取余的方法

1
2
3
4
// 将任意进制转成10进制
console.log(parseInt('11', 2));
// 将任意进制转成任意进制
console.log((0x16).toString(16));

在node中需要进行文件读取, node中操作的内容默认会存在内存中,内存中的表现形式肯定是二进制的,二进制转换16进制来展现 11111111 => ff

1
2
3
4
const fs = require('fs')
const path = require('path')
let r = fs.readFileSync(path.resolve(__dirname, 'test.md'))
console.log(r); // <Buffer 68 65 6c 6c 6f 20 6e 6f 64 65>
编码的发展
  • ASCII编码,一些常用的字符和字幕进行了一个排号, 大小(0 - 127), 只会占用一个字节大小, ASCII编码表 https://zh.wikipedia.org/wiki/ASCII

    1
    console.log(2**7 - 2**0); // 127,   1x2^(6+1) - 1x2^0
  • gb2312 用两个字节,大小(27000)

  • gbk 扩展 40000+
  • gb18030 少数民族的汉字
  • Unicode
  • utf8 (在utf8中一个字符占用一个字节, 一个汉字占用两(三)个字节)
    base64
    base64没有加密功能(只是编码转化base64), 原理是将3 8 的规则改成了4 6的规则, 什么意思呢, 就是
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 一、字符串转成16进制
    let buffer = Buffer.from('圳')
    console.log(buffer); // <Buffer e5 9c b3>

    // 二、16进制转成2进制
    console.log((0xe5).toString(2));
    console.log((0x9c).toString(2));
    console.log((0xb3).toString(2));
    // 3 * 8位规则的二进制
    // 11100101 10011100 10110011 => 111001011001110010110011
    // 4 * 6位规则的二进制
    // 111001011001110010110011 => 111001 011001 110010 110011

    // 三、二进制再转成十进制
    let arr = ['111001', '011001', '110010', '110011']
    arr = arr.map(v => parseInt(v, 2))
    console.log(arr);
    // [ 57, 25, 50, 51 ]

    // 四、再转成base64编码
    let str = ''
    str += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    str += str.toLowerCase()
    str += '0123456789'
    str += '+/'

    let base64 = ''
    arr.forEach((v) => { base64 += str[v] })
    console.log(base64); // 5Zyz

再反推回去就可以得到字符串了😅, 但是, 我就不, 但是在這里可以在线解密 base64.us

☂️ 为什么有的图片建议转成base64, 而有些图片不建议转成base64?

  • 原因是:举上面的例子,base64转化之前是e5 9c b3三个字符, 但是转换之后(5Zyz)是四个字节, 比原来大了三分之一, 比如原来1M的图片,base64之后比原来更大~, 所以只建议转小图片

☂️ 为什么叫base64, 因为分成每份的值永远不会大于64, 比如将一个二进制全填满

1
2
// 111001 => 111111 => 00111111
console.log(2 ** 6) // 64

前端的二进制(Blob二进制文件类型)

啥? 前端的文件不是file吗 ?

1
2
// 答案
<input type="file" /> // 继承于Blob

👉例如在前端我想下载, 和预览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="file" id="file">
<script>
let str = `<div>hello hardy</div>`
// 1、下载
// 字符串转成二进制类型 => 创建临时下载链接
const blob = new Blob([str], { type: 'text/html' })
const a = document.createElement('a')
a.setAttrbute('download', 'test.html')
a.href = URL.createObjectURL(blob)
a.click()

// 2、预览
file.addEventListener('change', function(e) {
let file = e.target.files[0]
let fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.onload = function () {
console.log(fileReader.result)
}
})
</script>
</body>
</html>

服务端的二进制(Buffer = 二进制数据, 内存)

Buffer可以和字符串相互转化, 不能扩容, 想改动就生成一个新的内存然后拷贝

三种声明方式

  • 通过长度声明(大小)

    1
    2
    3
    4
    5
    6
    const buffer = Buffer.alloc(5)   // 不具备扩展, push, shift等方法
    console.log(buffer.slice(0, 1)) // <Buffer 00 00 00 00 00> slice 浅拷贝

    let buf = buffer.slice(0, 1)
    buf[0] = 100
    console.log(buffer); // <Buffer 64 00 00 00 00>
  • 根据汉字声明(大小)

    1
    2
    const buffer = Buffer.from('小方块')
    console.log(buffer.length) // 9 1个汉字3个字符

.。。。待续更新