一、什么是 JavaScript 引擎

JavaScript 引擎是一个专门处理 JavaScript 代码的程序。它负责解析和执行 JavaScript 代码,将我们编写的 JavaScript 代码转换为机器能够理解和执行的机器码。

目前主流的 JavaScript 引擎有:

  • V8(Google):用于 Chrome 浏览器和 Node.js
  • SpiderMonkey(Mozilla):用于 Firefox 浏览器
  • JavaScriptCore(Apple):用于 Safari 浏览器
  • Chakra(Microsoft):用于 IE 和 Edge 浏览器(旧版)

二、主要组成部分

1. Memory Heap(内存堆)

  • 用于存储对象、数组等引用类型数据
  • 进行动态内存分配
  • 包含垃圾回收机制(分代回收、标记清除、引用计数等)
  • 处理内存碎片化问题

2. Call Stack(调用栈)

  • 记录代码执行的上下文
  • 基于 LIFO(后进先出)原则
  • 包含以下信息:
    • 局部变量
    • 参数
    • 返回地址
    • 临时变量

3. Parser(解析器)

解析过程分为两个阶段:

  1. 词法分析(Tokenization)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 源代码:let name = "John";
    // 被解析为 tokens:
    [
    { type: "keyword", value: "let" },
    { type: "identifier", value: "name" },
    { type: "operator", value: "=" },
    { type: "string", value: "John" },
    { type: "punctuator", value: ";" }
    ]
  2. 语法分析(生成 AST)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // AST 结构示例
    {
    type: "Program",
    body: [{
    type: "VariableDeclaration",
    declarations: [{
    type: "VariableDeclarator",
    id: {
    type: "Identifier",
    name: "name"
    },
    init: {
    type: "Literal",
    value: "John"
    }
    }]
    }]
    }

4. Interpreter(解释器)

  • 直接执行字节码
  • 维护执行上下文
  • 处理作用域链
  • 实现变量提升
  • 管理闭包

5. Compiler(编译器)

包含多个优化阶段:

  1. JIT(即时编译)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 热点函数会被编译优化
    function hotFunction(n) {
    // 被多次调用的函数
    return n * 2;
    }

    for(let i = 0; i < 100000; i++) {
    hotFunction(i); // 这个函数会被 JIT 编译
    }
  2. 内联缓存(Inline Caching)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 优化前
    function getName(obj) {
    return obj.name;
    }

    // V8 优化后的伪代码
    function getName(obj) {
    // 检查对象结构是否匹配缓存
    if (obj.map === cachedMap) {
    // 直接返回固定偏移量的属性
    return *(obj + nameOffset);
    }
    // 回退到常规属性访问
    return obj.name;
    }

三、工作流程

1. 加载阶段

  1. 源码加载
  2. 词法分析
  3. 语法分析
  4. 生成 AST
  5. 生成字节码

2. 执行阶段

  1. 创建执行上下文

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ExecutionContext = {
    ThisBinding: <this value>,
    LexicalEnvironment: {
    EnvironmentRecord: {
    Type: "Declarative",
    // 标识符绑定
    },
    outer: <outer lexical environment reference>
    },
    VariableEnvironment: {
    EnvironmentRecord: {
    Type: "Declarative",
    // 变量和函数声明
    },
    outer: <outer lexical environment reference>
    }
    }
  2. 作用域链建立

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function outer() {
    const a = 1;
    function inner() {
    const b = 2;
    console.log(a, b);
    }
    return inner;
    }
    // 作用域链:inner -> outer -> global
  3. 变量对象创建

  4. 代码执行

3. 优化阶段

  1. 死代码消除

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 优化前
    function unused() {
    const a = 1;
    const b = 2;
    return a; // b 永远不会被使用
    }

    // 优化后
    function unused() {
    const a = 1;
    return a;
    }
  2. 内联展开

    1
    2
    3
    4
    5
    6
    7
    8
    // 优化前
    function add(a, b) {
    return a + b;
    }
    let result = add(1, 2);

    // 优化后
    let result = 1 + 2;

四、性能优化

1. 代码层面

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
31
32
33
34
35
36
37
// 1. 对象属性访问优化
const obj = {
name: 'John',
age: 30
};

// 不推荐
function badAccess() {
for(let i = 0; i < 1000; i++) {
console.log(obj.name); // 每次都要查找属性
}
}

// 推荐
function goodAccess() {
const { name } = obj; // 解构一次
for(let i = 0; i < 1000; i++) {
console.log(name);
}
}

// 2. 函数优化
// 不推荐
const addBad = new Function('a', 'b', 'return a + b');

// 推荐
const addGood = (a, b) => a + b;

// 3. 数组优化
// 不推荐
const arrBad = new Array(1000);
for(let i = 0; i < arrBad.length; i++) {
arrBad[i] = i;
}

// 推荐
const arrGood = Array.from({ length: 1000 }, (_, i) => i);

2. 内存管理

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
// 1. WeakMap 使用
const cache = new WeakMap();
function memorize(fn) {
return function(obj) {
if (!cache.has(obj)) {
cache.set(obj, fn(obj));
}
return cache.get(obj);
}
}

// 2. 避免内存泄漏
class EventEmitter {
constructor() {
this.listeners = new Map();
}

addListener(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
}

removeListener(event, callback) {
if (this.listeners.has(event)) {
this.listeners.get(event).delete(callback);
}
}
}

五、注意事项

1. 内存泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1. 闭包导致的内存泄漏
function createLeak() {
const largeData = new Array(1000000);
return function() {
console.log(largeData.length);
}
}

// 2. 定时器未清除
function setTimer() {
const data = { /* 大量数据 */ };
const timer = setInterval(() => {
console.log(data);
}, 1000);

// 记得清除
return () => clearInterval(timer);
}

2. 执行效率

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1. 避免动态属性访问
const key = 'dynamicKey';
obj[key] = value; // 会禁用某些优化

// 2. 使用位运算
// 不推荐
Math.floor(num / 2);
// 推荐
num >> 1;

// 3. 避免混合类型
let number = 42;
number = 'string'; // 会导致类型转换,降低性能

六、高级优化技巧

1. Hidden Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 不推荐
function Point(x, y) {
this.x = x;
this.y = y;
if (x > 0) {
this.positive = true; // 动态添加属性
}
}

// 推荐
function Point(x, y) {
this.x = x;
this.y = y;
this.positive = x > 0; // 固定属性结构
}

2. 函数优化

1
2
3
4
5
6
7
8
9
10
11
// 1. 单态函数
function add(a, b) {
// 只处理数字类型
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
throw new Error('Invalid arguments');
}

// 2. 内联优化
const multiply = (a, b) => a * b; // 简单函数更容易被内联

参考文献