JavaScript
JavaScript 基础
一、Nodejs, Js, npm 的关系
JavaScript 是一种动态、弱类型、解释型的脚本语言(基于 C++ 封装)
Node.js 是基于 Chrome V8 引擎构建的 JavaScript Runtime,目的是能 js 在服务端上运行
npm(Node Package Manager) 是 Nodejs 的官方包管理工具,目的是管理第三方代码依赖
三者关系是:
1 | |
二、隔离不同项目依赖
不像 python 有 venv, Js 是通过本地 node_modules + 锁定文件来实现逻辑上的隔离
每个项目有自己的 node_modules 目录
比如执行 npm install ioredis 的时候,包会被安装到当前项目目录下的 ./node_modules。
不同项目的 node_modules 互不影响
依赖解析规则(
当代码中写 const Redis = require('ioredis') 的时候,Node.js 会:
- 优先在 当前项目
node_modules中找; - 如果没有,逐级向上查找父目录的
node_modules,直到根目录; - 不会自动使用全局安装的包(除非显式指定)。
锁定依赖版本
npm install 下载生成的 package-lock.json 记录精确版本号 + 依赖树结构。
团队成员执行 npm ci 可重建完全一致的 node_modules。
三、JavaScript 的内存管理
内存分配机制
Js 引擎在运行时自动推断值的类型,并为其分配合适内存:
1 | |
其中基本类型(number, string, boolean, symbol)小整数或短字符串可能直接内联存储(栈或对象内),大值存在堆上
引用类型(Object, Array, Function) 总是分配在堆上,
垃圾回收机制
Js 的内存管理机制是自动垃圾回收(GC),C++ 现在则是利用 RAII 思想来析构对象,可以直接用智能指针来管理对象
后现代语言通常采用 GC 机制回收变量,当创建的对象不再被使用的时候就会变成 “垃圾”,被 GC 自动回收。
识别核心也是:
- 引用计数(存在循环引用问题):每个对象有计数器,被引用一次,计数就 + 1,引用消失,计数就 -1,为 0 时就被回收
- 可达性分析:从 “根对象”(全局变量,栈变量,当前执行上下文)开始遍历,能遍历到的 = 活着,遍历不到 = 垃圾
回收核心则是:
- 分代回收(Java/JS v8 核心):把对象分为 ”新对象“/”老对象“,其中新生代对象死得快,GC 频繁,老生代对象活得久,GC 少(效率高)
- Mark-Sweep:先标记所有可达对象,再清除未标记的垃圾
- Mark-Compact:标记 → 把存活对象往一边挤 → 清除剩下的垃圾,这样能够解决碎片问题
GC 的缺点很明显:
- GC 工作时,会有停顿(STW),影响系统性能
- GC 本身会有开销,占 CPU,内存