Node.js 全局对象

  1. JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量;

  2. 在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global ,所有全局变量(除了 global 本身以外)都是 global 对象的属性;

  3. Node.js 可以直接访问到 global 的属性,而不需要在应用中包含它;

global 中常用属性

__filename

  • __filename 表示当前正在执行的脚本的文件名,输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同;

  • 如果在模块中,返回的值是模块文件的路径;

console.log( __filename );
// /Users/wushuai/Desktop/frontend-node-master/全局对象/index.js

__dirname

__dirname 表示当前执行脚本所在的目录

console.log(__dirname);
// /Users/wushuai/Desktop/frontend-node-master/全局对象

setTimeout(cb, ms)

  • setTimeout(cb, ms) 全局函数在指定的毫秒 (ms) 数后执行指定函数 (cb)setTimeout() 只执行一次指定函数;

  • 返回一个代表定时器的句柄值;

  • JavaScriptsetTimeout 使用方式一样;

clearTimeout(t)

  • clearTimeout(t) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器;

  • JavaScriptclearTimeout 使用方式一样;

setInterval(cb, ms)

  • setInterval(cb, ms) 全局函数在指定的毫秒 (ms) 数后执行指定函数 (cb)setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭;

  • 返回一个代表定时器的句柄值;

  • JavaScriptsetInterval 使用方式一样;

clearInterval(t)

  • clearInterval(t) 全局函数用于停止一个之前通过 setInterval() 创建的定时器;

  • JavaScriptclearInterval 使用方式一样;

console

  • console 用于提供控制台标准输出,它是由 Internet ExplorerJScript 引擎提供的调试工具,后来逐渐成为浏览器的实施标准;

  • Node.js 沿用了这个标准,提供与习惯行为一致的 console 对象,用于向标准输出流(stdout)或标准错误流(stderr)输出字符;

  1. console.log:向标准输出流打印字符并以换行符结束

  2. console.info:该命令的作用是返回信息性消息

  3. console.error:输出错误消息的

  4. console.warn:输出警告消息

  5. console.dir:用来对一个对象进行检查(inspect),并以易于阅读和打印的格式显示

  6. console.time:输出时间,表示计时开始

  7. console.timeEnd:结束时间,表示计时结束

  8. console.trace:输出当前执行的代码在堆栈中的调用路径

  9. console.assert:用于判断某个表达式或变量是否为真,接收两个参数,第一个参数是表达式,第二个参数是字符串;只有当第一个参数为false,才会输出第二个参数,否则不会有任何结果

process

用于描述当前 Node.js 进程状态的对象,提供了与操作系统交流的接口;

  1. process.argv 是命令行参数数组:

    $ node argv.js 1991 name=byvoid --v "Carbo Kuo" 
    
    # 第一个返回参数是 node;
    # 第二个是文件路径及文件名;
    # 第三个后面每个元素是一个运行参数;
    [ 'node',   
      '/home/byvoid/argv.js',  
      '1991',   
      'name=byvoid',  
      '--v',   
      'Carbo Kuo' 
    ]
    
  2. process.stdout

    • process.stdout 是标准输出流,通常使用 console.log() 输出打印字符;
    • process.stdout.write() 函数提供了更底层的接口;
  3. process.stdin:标准输入流,初始时是被暂停的状态,想要输入数据,首先必须恢复流,并手动编写流事件的响应函数;

    //重启恢复
    process.stdin.resume();
    
    //编写流事件响应函数
    process.stdin.on('data',function(data)) {
      process.stdout.wtite('read from console :' + data.toString());
    }
    
  4. process.nextTick(callback):为事件循环设置一项任务,nodejs 会在下次事件循环响应时调用 callback

  5. process.version:一个暴力 node 版本(NODE_VERSION)的内编译属性;

  6. process.versions:一个暴露 nodejs 版本和其依赖的属性;

  7. process.arch:系统运行的处理器的架构:“arm”、“ia32”、“x64”、…;

  8. process.platform:运行的系统环境 ‘linux2’、‘darwin’ 等;

  9. process.memoryUsage():返回字节码为单位的 node 进程的内存使用情况描述对象;

  10. process.uptime():node 运行的时间,秒;

  11. process.cwd():当前用户的工作目录;

Buffer

  • Buffer 一般称之为 Buffer 缓冲区,让 JavaScript 可以操作二进制;

  • JavaScript 语言起初服务于浏览器平台,因此它内部主要操作的数据类型就是字符串;

  • Nodejs 的出现使得可以在服务端使用 JavaScript 进行编程,完成 IO 操作,例如文件的读写、网络服务中数据的传输等,在这个过程中就是用到了 Buffer

  • Buffer 一般配合 Stream 流使用,充当数据缓冲区;

Buffer 存在的意义

  1. 程序运行就会进行二进制的数据传输,而这个传输一般都是由 fromto 的过程,即数据的 生产者 和数据的 消费者 ,中间就会使用流配合管道进行连接;但是这个模型在实际工作的时候也会出现问题,比如数据的生产速度无法满足数据的消费速度,又或者数据的消费速度比生产速度慢了许多;

  2. 总归来说,不论出现哪种情况,数据都会有一个等待的过程,等待的时候那些多出来的数据,或者还不够一次消费的数据被存放在哪里呢?

    • 这个时候就有了 Buffer ,所以也称为 Buffer 缓冲区;
    • NodejsBuffer 就是一片内存空间,只不过这个内存空间有些特殊;
    • Nodejs 中的代码最终都是由 V8 引擎执行完成的,因此理论上所有的内存消耗应该都属于 V8 的堆内存,而 BufferV8 之外的一片空间,它的大小不占据 V8 堆内存的大小;通过 process.memoryUsage() 获取内存消耗的信息中有一个 arrayBuffers ,指的就是 Buffer 申请的内存;
    • Buffer 的空间申请不是由 Node 完成的,但是在使用层面上,它的空间分配又是由开发者编写的 JS 代码控制的,因此在空间回收的时候,它还是由 V8GC(垃圾回收) 管理和回收,开发者无法参与其中;

创建 Buffer 实例

  1. 三种通过 Buffer 静态方法创建实例对象(不能扩容):

    • Buffer.alloc 创建指定字节大小的 buffer
    TS
    JS
    Buffer.alloc(size: number, fill?: string | number | Buffer, encoding?: BufferEncoding): Buffer
    
    const b1 = Buffer.alloc(10) // 创建空间大小是 10 字节的 buffer
    
    // buffer 会以 16 进制格式存储每个字节的数据
    console.log(b1) // <Buffer 00 00 00 00 00 00 00 00 00 00>
    
    • Buffer.allocUnsafe 创建指定字节大小的 buffer(不安全),不会向创建的内存填充数据;
    TS
    JS
    Buffer.allocUnsafe(size: number): Buffer
    
    const b2 = Buffer.allocUnsafe(10)// 创建空间大小是 10 字节的 buffer
    
    // buffer 会以 16 进制格式存储每个字节的数据
    console.log(b2) // <Buffer 00 00 00 00 a0 00 00 00 00 00>
    
    • Buffer.from 接收数据,创建 buffer(与前两者的区别是创建默认带数据的 buffer);
    TS
    JS
    Buffer.from(arrayBuffer: WithImplicitCoercion < ArrayBuffer | SharedArrayBuffer >, byteOffset?: number, length?: number): Buffer
    
    const b3 = Buffer.from('中') // utf8 一个汉字用 3 个字节表示
    console.log(b3) // <Buffer e4 b8 ad>
    console.log(b3.toString()) // 中
    
    // 第一个参数是数组,数组元素应该都是数字格式(十进制、八进制或十六进制等),否则会被忽略
    const b4 = Buffer.from([1, 2, '中']) // 汉字会被忽略
    console.log(b4) // <Buffer 01 02 00>
    // 将汉字中替换成数字
    const b5 = Buffer.from([228 /* 0xe4 的十进制 */ , 0270 /* 0xb8 的八进制 */ , 0xad]) 
    console.log(b5) // <Buffer e4 b8 ad>
    console.log(b5.toString()) // 中
    
    // 第一个参数是 buffer,创建的 buffer 只是传入的 buffer 的拷贝,并不会共享空间
    const b6 = Buffer.alloc(3)
    const b7 = Buffer.from(b6)
    b6[0] = 1
    console.log(b6) // <Buffer 01 00 00>
    console.log(b7) // <Buffer 00 00 00>
    
  2. 为什么不使用 new 创建 Buffer

    • Nodejsv6 版本之前可以直接通过 new 实例化 Buffer 对象,但是这种方式提供给 Buffer 实例对象的操作权限实在是太大了,所以在后续的版本中对它进行了一些处理;
    • 主要还是使用这种方式分配的内存是没有初始化过的,包含敏感数据,Node.js 认为在分配内存的安全性上需要更加明确的区分,所以建议使用 Buffer 类的静态方法创建,而不是通过 new 实例化;
  3. 为什么 allocUnsafe 不安全?

    • 关键在于给 Buffer 申请分配的内存是否被初始化,被初始化的内存即填充了默认的数据(例如 0),没被初始化的内存可能包含敏感的旧数据,这是不安全的;
    • Buffer.alloc() 分配的内存是初始化过的内存(被 0 填满覆盖),这种创建方式虽然慢但被认为是安全的;
    • Buffer.allocUnsafe() 分配的内存没有被初始化,所以分配速度相当快,但内存中可能存在敏感旧数据,在 Buffer 可读的情况下,可能会泄露数据,这种方式被认为是不安全的,一般会建议手动通过 buf.fill(0) 初始化或写满这个 Buffer
    • 虽然在使用 Buffer.allocUnsafe() 时有明显的性能优势,但必须额外小心,以避免给应用程序引入安全漏洞;

Buffer 实例方法

  1. buffer.fill(value: string | number | Uint8Array, offset?: number, end?: number, encoding?: BufferEncoding): Buffer

    fill:向 buffer 中反复填充数据,直到填满,返回填充后的 buffer

    // 创建一个空的 buffer
    const buf = Buffer.alloc(6)
    
    buf.fill('123') // 反复填充直到填满
    console.log(buf) // <Buffer 31 32 33 31 32 33>
    console.log(buf.toString()) // 123123
    
    buf.fill('123456789')
    console.log(buf.toString()) // 123456
    
    buf.fill('0').fill('123', 1) // 第二个参数:跳过填充的字节数
    console.log(buf.toString()) // 012312
    
    buf.fill('0').fill('123', 1, 3) // 第三个参数:停止填充的位置索引
    console.log(buf.toString()) // 012000
    
    buf.fill(123) // 如果填充的是数字,则转化成十六进制填充
    console.log(buf) // <Buffer 7b 7b 7b 7b 7b 7b>
    console.log(buf.toString())
    
  2. buffer.write(string: string, offset: number,length:length, encoding?: BufferEncoding): number

    write:向 buffer 中写入数据,返回写入的字节数

    // 创建一个空的 buffer
    const buf = Buffer.alloc(6)
    
    // 与 fill 类似,但只会写入一次
    buf.write('123')
    console.log(buf) // <Buffer 31 32 33 00 00 00>
    console.log(buf.toString()) // 123
    
    buf.fill(0).write('123', 1) // 第二个参数表示跳过填充的字节数
    console.log(buf) // <Buffer 00 31 32 33 00 00>
    
    buf.fill(0).write('123', 1, 2) // 第三个参数是写入的字节数
    console.log(buf) // <Buffer 00 31 32 00 00 00>
    
  3. buffer.toString(encoding?: BufferEncoding, start?: number, end?: number): string

    toString:根据指定的字符编码将 buffer 解码为字符串

    // 创建一个空的 buffer
    const buf = Buffer.from('abc你好')
    
    console.log(buf) // <Buffer 61 62 63 e4 bd a0 e5 a5 bd>
    console.log(buf.toString()) // abc你好
    console.log(buf.toString('utf8', 1, 6)) // bc你
    
  4. buffer.slice(start?: number, end?: number): Buffer

    slice:截取 buffer ,类似数组的 slice

    const buf = Buffer.from('abc你好')
    
    const b1 = buf.slice(1, 6)
    console.log(b1) // <Buffer 62 63 e4 bd a0>
    console.log(b1.toString()) // bc你
    
  5. buffer.indexOf(value: string | number | Uint8Array, byteOffset?: number, encoding?: BufferEncoding): number

    indexOf:类似数组的 indexOf

    const b2 = Buffer.from('a你b好a你b好')
    
    console.log(b2.indexOf('你')) // 1
    console.log(b2.indexOf('b')) // 4
    console.log(b2.toString().indexOf('b')) // 2
    console.log(b2.indexOf('b', 5)) // 12
    
  6. buffer.copy(target: Uint8Array, targetStart?: number, sourceStart?: number, sourceEnd?: number): number

    copy:从 buffer 数据源拷贝数据到目标 buffer

    const b1 = Buffer.from('你好abcde')
    const b2 = Buffer.alloc(6)
    
    b1.copy(b2)
    console.log(b1) // <Buffer e4 bd a0 e5 a5 bd 61 62 63 64 65>
    console.log(b1.toString()) // 你好abcde
    console.log(b2) // <Buffer e4 bd a0 e5 a5 bd>
    console.log(b2.toString()) // 你好
    
    const b3 = Buffer.alloc(6)
    b1.copy(b3, 2, 3, 7)
    console.log(b3) // <Buffer 00 00 e5 a5 bd 61>
    console.log(b3.toString()) // 好
    
  7. buffer.split

    split:buffer 分割(手动实现,Buffer 实例并未提供)

    Buffer.prototype.split = function (separator) {
      const len = Buffer.from(separator).length // 获取分割符字节数
    
      let res = [] // 最终返回结果
      let start = 0 // 查询起始位置
      let offset = 0 // 偏移量
    
      while ((offset = this.indexOf(separator, start)) !== -1) {
          res.push(this.slice(start, offset))
          start = offset + len
      }
    
      // 处理结尾是分隔符的情况,追加尾部
      res.push(this.slice(start))
    
      return res
    }
    
    const buf = Buffer.from('夫战,勇气也,一鼓作气,再而衰,三而竭,彼竭我盈,顾克之,')
    console.log(buf.split(',').map(v => v.toString()))
    // [ '夫战', '勇气也', '一鼓作气', '再而衰', '三而竭', '彼竭我盈', '顾克之', '']
    

Buffer 静态方法

  1. Buffer.concat(list: readonly Uint8Array[], totalLength?: number): Buffer

    concat:将多个 Buffer (数组)拼接成一个新的 Buffer ,便于获取多个 Buffer 组成的数据

    const b1 = Buffer.from('你好')
    const b2 = Buffer.from('世界')
    
    const b3 = Buffer.concat([b1, b2])
    console.log(b3.toString()) // 你好世界
    
    const b4 = Buffer.concat([b1, b2], 9)
    console.log(b4.toString()) // 你好世
    
  2. Buffer.isBuffer(obj: any): obj is Buffer

    isBuffer:判断当前数据是否是 Buffer 类型

    const b1 = Buffer.from('你好')
    
    console.log(Buffer.isBuffer([])) // false
    console.log(Buffer.isBuffer('123')) // false
    console.log(Buffer.isBuffer(b1)) // true
    

base64 原理

二进制 3 * 8 的规则 改成了 4 * 6 的规则

let buffer = Buffer.from('我'); // 将字符串转化成 16 进制
console.log(buffer); // e6 88 91

// 16进制 => 2进制
console.log((0xe6).toString(2)); // 11100111
console.log((0x88).toString(2)); // 10001111
console.log((0x91).toString(2)); // 10100000

// base64规则:将 3*8(11100111 10001111 10100000)的规则转成 4*6(111001 111000 111110 100000)的规则

// 2进制 => 10进制
console.log(parseInt('111001', 2)); // 57
console.log(parseInt('111000', 2)); // 56
console.log(parseInt('111110', 2)); // 62
console.log(parseInt('100000', 2)); // 32

// base64 编码表:
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

// 最后转成 base64 格式的数据
// 转成 base64 后(3beat => 4beat),比原来大了 三分之一
console.log(str[57] + str[56] + str[62] + str[32]);  // 54+g

前端二进制操作

  1. 前端实现下载功能

    <!-- 将字符串包装成二进制文件类型 Blob -->
    <body>
      <script>
        let str = `你好`;
        // 包装后的文件类型不能直接修改
        const blob = new Blob([str], { type: 'text/html' });
    
        const a = document.createElement('a');
        a.setAttribute('download', 'index.txt');
        a.href = URL.createObjectURL(blob);
        a.click();
      </script>
    </body>
    
  2. 前端实现预览功能

    <!-- 将二进制文件转成临时 url -->
    <body>
      <input type="file" id="file">
      <script>
        file.addEventListener('change', (e) => {
          let file = e.target.files[0]; //二进制文件类型
    
          let img = document.createElement('img');
          let url = URL.createObjectURL(file);
          img.src = url;
          document.body.appendChild(img);
        })
      </script>
    </body>
    
  3. 前端实现预览功能

    <!-- fileReader 读取二进制中内容 -->
    <body>
      <input type="file" id="file">
      <script> 
        file.addEventListener('change', (e) => {
          let file = e.target.files[0]; //二进制文件类型
    
          let fileReader = new FileReader();
          fileReader.readAsDataURL(file);
    
          fileReader.onload = function () {
            let img = document.createElement('img');
            img.src = fileReader.result;
            document.body.appendChild(img)
          }
        })
      </script>
    </body>
    
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. Node.js 全局对象
  2. 2. global 中常用属性
    1. 2.1. __filename
    2. 2.2. __dirname
    3. 2.3. setTimeout(cb, ms)
    4. 2.4. clearTimeout(t)
    5. 2.5. setInterval(cb, ms)
    6. 2.6. clearInterval(t)
    7. 2.7. console
    8. 2.8. process
    9. 2.9. Buffer
      1. 2.9.1. Buffer 存在的意义
      2. 2.9.2. 创建 Buffer 实例
      3. 2.9.3. Buffer 实例方法
      4. 2.9.4. Buffer 静态方法
      5. 2.9.5. base64 原理
      6. 2.9.6. 前端二进制操作