3.值类型 vs 引用类型 副本.md

查看飞书原文 ↗2,880 字符

1. 核心概念 (Core Concept)

JavaScript 的数据类型根据其在内存中的存储方式,分为值类型 (Value Types) 和引用类型 (Reference Types)。

2. 为什么需要理解它们?

  1. 预测变量行为: 理解值类型和引用类型的差异是预测变量在赋值、传参等操作后行为的基础。错误地认为引用类型是按值复制,会导致难以调试的 bug。
  2. 理解函数传参机制: JavaScript 函数的参数传递始终是"按值传递" (pass by value)。对于值类型,是传递值的副本;对于引用类型,是传递引用的副本。这解释了为什么在函数内部修改引用类型参数的属性会影响到外部对象。
  3. 掌握深浅拷贝的基础: 深拷贝和浅拷贝的概念完全建立在值类型和引用类型的基础之上。只有理解了引用,才能明白为什么需要深拷贝。

3. API 与用法

值类型 (Value Types)

包括 String, Number, Boolean, Null, Undefined, Symbol, BigInt。

let a = 100;
let b = a; // b 是 a 的一个副本

a = 200; // 修改 a 的值

console.log(a); // 输出: 200
console.log(b); // 输出: 100 (b 的值不受影响)

内存图解:

引用类型 (Reference Types)

包括 Object, Array, Function 等。

let obj1 = { name: 'Alice' };
let obj2 = obj1; // obj2 复制的是指向 { name: 'Alice' } 的引用

obj1.name = 'Bob'; // 通过引用修改堆内存中的对象

console.log(obj1.name); // 输出: 'Bob'
console.log(obj2.name); // 输出: 'Bob' (obj2 也指向同一个对象,因此也受到影响)

内存图解:

4. 关键注意事项 (Key Considerations)

  1. 函数参数传递:

    • 传递值类型:函数内部对参数的修改不会影响外部变量。
    • 传递引用类型:函数内部修改参数对象的属性会影响外部对象。但如果函数内部将参数重新赋值为一个新对象,则会切断与外部对象的联系。
    function modify(obj) {
      // 修改属性,会影响外部
      obj.name = 'Modified';
    
      // 重新赋值,不会影响外部
      obj = { name: 'New Object' };
    }
    
    let myObj = { name: 'Initial' };
    modify(myObj);
    console.log(myObj.name); // 输出: 'Modified'
    
  2. const 和引用类型: const 声明一个引用类型的变量时,仅保证变量存储的引用(地址)不可变,但该引用指向的对象内容是可变的。

    const user = { name: 'John' };
    user.name = 'Jane'; // 合法
    // user = { name: 'Doe' }; // 非法, TypeError
    
  3. 判断相等 (== 或 ===):

    • 对于值类型,比较的是它们的值。
    • 对于引用类型,比较的是它们是否指向同一个内存地址(引用)。两个内容完全相同的独立对象,比较结果也是 false。
    console.log({} === {}); // false
    

5. 参考资料 (References)


原文链接与附件索引