根因:JS 最初为网页交互而生,是单线程、解释型、弱类型的脚本语言。
整套体系分:语法基础、执行底层、原型与面向对象、异步、DOM/BOM、ES6+、作用域、类型系统。
一、基础核心术语
- 词法分析(Lexical Analysis)
引擎读取源码,拆分成最小单元「词元(token)」:关键字、标识符、运算符、字符串、数字。 - 语法分析(Parsing)
将token生成AST 抽象语法树。JS引擎基于AST生成字节码,交给解释器执行。 - 解释型语言
不需要提前把全部源码编译成机器码;边解释边执行。现代V8是即时编译JIT,解释+编译结合。 - 弱类型语言
变量不绑定固定类型,允许隐式类型转换。0 == false这类就是弱类型带来的特性。 - 动态类型
变量的类型在运行期确定,不是写代码的时候确定。同一个变量可以先后存字符串、数字。 - 声明 vs 定义
- 声明:告诉引擎存在这个变量
let a; - 定义:给变量赋值
a = 10
- 声明:告诉引擎存在这个变量
- 标识符 Identifier
变量名、函数名、属性名。只能字母、数字、$、_,不能数字开头,不能是关键字。 - 关键字 / 保留字
语言内置预留单词:let、const、function、if、class,不能用作变量名。
二、数据类型
JS 一共8种数据类型,分为原始类型、引用类型
原始类型(基本类型,存栈内存)
- Undefined:变量已声明,未赋值,默认值。
- Null:空值。
typeof null === 'object'历史bug。 - Boolean:布尔,
true / false - Number:数字,包含整数、浮点数;存在0.1+0.2精度丢失(IEEE754双精度浮点数)
- String:字符串,不可变。字符串一旦创建不能修改,只能新建。
- Symbol:ES6,唯一不可重复的值,用作对象私有属性key。
- BigInt:ES2020,大整数,解决Number大数丢失精度问题。
引用类型(存堆内存,变量存内存地址引用)
- Object对象类型。普通Object、Array、Function、Date、RegExp都属于Object的子类。
- 装箱转换:原始值临时包装成对应的包装对象,调用方法。例:
"abc".length,后台临时创建String对象。 - 拆箱转换:包装对象变回原始值。
三、作用域 & 变量提升
- 作用域 Scope:变量可访问的范围。
- 全局作用域:页面全局,任何地方可访问
- 函数作用域:function内部
- 块级作用域:
{},let/const才有,var没有
- 词法作用域(静态作用域)
作用域在写代码阶段就确定,不是运行时决定。JS采用词法作用域。 - 变量提升 Hoisting
代码执行前,扫描整个作用域,把var变量、函数声明提升到作用域顶部。let/const存在提升,但有暂时性死区TDZ,不能在声明前访问。 - 暂时性死区 TDZ
从块作用域开始,直到let/const声明语句之前,这个区间不能访问该变量,直接报错。 - 闭包 Closure
内层函数,引用外层函数作用域的变量;外层函数执行结束,作用域本应销毁,但因为闭包引用,变量保留。根因:函数可以携带它诞生时的词法环境。风险:内存不释放,容易内存泄漏。
- 垃圾回收 GC
V8自动回收不再被引用的堆内存。标记清除为主。
闭包、全局事件监听、DOM引用不释放,会造成内存泄漏。
四、原型与面向对象(JS灵魂)
- 原型 prototype
每个函数都有prototype属性(显式原型)。 - proto(隐式原型)
每个对象都有__proto__,指向构造函数的prototype。 - 原型链
对象查找属性时:自身 →obj.__proto__→obj.__proto__.__proto__,直到null。
如果整条链找不到属性,返回undefined。 - 构造函数 Constructor
用来生成对象的函数,配合new。 - new 关键字执行流程
- 创建空{}
- 空对象
__proto__指向构造函数prototype - 绑定this到空对象,执行构造函数代码
- 如果函数没有返回对象,默认返回新建对象
- this:动态绑定的关键字,指向调用函数的调用主体
- 全局:this指向全局对象window
- 对象方法:this = 调用方法的对象
- new构造函数:this是新实例
- call / apply / bind:手动绑定this
- 箭头函数:没有自己的this,继承外层词法环境的this,无法bind/call修改
五、函数相关术语
- 函数声明 function fn(){}存在提升
- 函数表达式 const fn = function(){}不存在提升
- 箭头函数 ()=>{}:无this、无arguments,不能用作构造函数new
- 高阶函数:参数是函数 / 返回值返回函数。例如:map、filter、Promise、debounce
- 纯函数:相同输入一定得到相同输出;无副作用(不修改外部变量、不操作DOM、不发请求)。
- 副作用 Side Effect:函数修改外部状态,比如修改全局变量、DOM、网络请求。
- arguments:类数组对象,保存函数全部入参;箭头函数没有arguments。
- 剩余参数 …rest,ES6,收集剩余参数,是真正数组。
六、异步模型
JS 是单线程,异步靠事件循环。
- 同步任务:主线程依次执行,做完一个才下一个,阻塞。
- 异步任务:不会阻塞主线程,任务完成后放入队列。
- 事件循环 Event Loop
主线程执行栈清空,去任务队列取任务,放到执行栈执行,循环往复。 - 宏任务 MacroTask:setTimeout、setInterval、I/O、script整体代码
- 微任务 MicroTask:Promise.then/catch/finally、MutationObserver、queueMicrotask
优先级:同步代码 > 微任务全部执行完毕 > 一个宏任务
- Promise
异步容器,代表一个未来才会完成的异步操作。三种状态:pending / fulfilled / rejected。状态一旦确定不可变更。 - async / await:Promise语法糖。async函数永远返回Promise;await后面等待Promise完成,await会让出主线程,暂停当前async函数。
- 回调函数 Callback:把函数传给别人,等任务结束后调用。回调地狱:多层回调嵌套,可读性差。
七、ES6+ 常用术语
- 解构 Destructuring:数组/对象快速取出属性
const {name} = user - 展开运算符 …
- 对象:浅拷贝对象;数组:展开数组
- 模板字符串
`hello ${name}` - 模块 Module(ESM)
import / export,浏览器/Node原生模块化,静态导入,编译期分析依赖。
对比 CommonJS:Node旧规范require/module.exports,运行时加载。 - 类 Class:原型面向对象的语法糖,底层仍然是原型链。
- Promise.all / race / allSettled / any并发控制API
- 可选链 ?.:
user?.info?.name,防止属性不存在报错 - 空值合并 ??:
const a = b ?? 10,仅当b为null/undefined才取默认值,和||区分。
八、DOM & BOM
- DOM 文档对象模型:HTML文档映射成JS可操作的对象树。
- BOM 浏览器对象模型:浏览器窗口相关API:window、location、history、navigator
- 事件流:捕获阶段 → 目标阶段 → 冒泡阶段
- 事件委托(事件代理):利用事件冒泡,父元素监听子元素事件,减少事件绑定数量。
- 重排(回流)Reflow:DOM布局几何变化,浏览器重新计算元素位置大小,开销大。
- 重绘 Repaint:元素颜色、背景色改变,只重新绘制像素,不改变布局。
九、数组相关术语
- 迭代器 Iterator:
Symbol.iterator,for…of依靠迭代器遍历 - 伪数组(类数组):有length、索引,没有数组原型方法,如arguments、DOM集合。可以
Array.from转为数组。 - 数组方法:forEach、map、filter、reduce、some、every。
map返回新数组;forEach无返回值。
十、易错辨析术语
==宽松相等:隐式类型转换后比较;===严格相等,不做类型转换,推荐使用。- 浅拷贝:只拷贝第一层,嵌套对象仍然共用引用;Object.assign、展开运算符
{...obj} - 深拷贝:递归复制所有层级,完全独立。JSON.parse(JSON.stringify)简易版,有缺陷(不能处理函数、Symbol、循环引用)。
JS是单线程弱类型解释型脚本语言,V8引擎采用JIT即时编译;数据分为原始类型(栈)和引用类型(堆);采用词法作用域,闭包保留词法环境;依靠原型链实现继承;异步基于事件循环,区分宏任务微任务;ES6提供Promise、async/await、ESM模块等能力;通过DOM/BOM操作页面与浏览器。