红宝书第四讲:JavaScript原始值与引用值行为差异详解

资料取自《JavaScript高级程序设计(第5版)》
查看所有教程:红宝书学习大纲


一、基本定义与存储方式

  1. 原始值(Primitive Values)

    • 类型:包括字符串(String)、数字(Number)、布尔值(Boolean)、nullundefinedSymbolBigInt1
    • 存储方式:直接存储在栈内存中,占用固定大小空间。例如一个数字或字符串直接保存其实际值1
  2. 引用值(Reference Values)

    • 类型:对象(Object)、数组(Array)、函数(Function)等。
    • 存储方式:实际数据存储在堆内存中,变量保存的是指向堆内存的指针地址1

二、变量复制时的差异

  1. 原始值的复制:独立拷贝

    • 复制后,新旧变量完全独立。

      let num1 = 5;
      let num2 = num1; // 复制值本身
      num1 = 10;
      console.log(num2); // 输出5(num2不受num1修改影响)[^2]
  2. 引用值的复制:共享对象

    • 复制的是指针地址,新旧变量指向同一个对象:

      let obj1 = { name: "Alice" };
      let obj2 = obj1;   // 复制指针地址
      obj1.name = "Bob"; 
      console.log(obj2.name); // 输出"Bob"(通过指针修改同一对象)[^2]

三、动态属性操作能力

  1. 引用值可动态增删属性

    • 对象可以随时添加或删除属性:

      let person = {};        // 空对象
      person.name = "Alice";  // 新增属性
      delete person.name;     // 删除属性[^4]
  2. 原始值无法添加属性

    • 即使试图添加属性,也不会保留:

      let name = "Charlie";
      name.age = 30;          // 不会报错,但无意义
      console.log(name.age);  // 输出undefined[^4]

四、类型检测与包装对象

  1. 类型检测工具

    • typeof:返回原始值的类型(如 "string""number"),但引用值统一返回 "object"(函数返回 "function")1
    • instanceof:用于检测引用值是否属于某个类(如 [] instanceof Array 返回 true1
  2. 原始包装对象的特殊行为

    • 原始值调用方法时临时创建对象包装器:

      let s = "hello";
      console.log(s.substring(1)); // 临时转换为String对象调用方法[^5]
    • 包装对象与原始值的区别:

      let a = "text";
      let b = new String("text"); 
      console.log(typeof a); // "string"(原始值)
      console.log(typeof b); // "object"(引用值)[^1]

五、典型陷阱:原始值与包装对象的逻辑差异

  1. 布尔值的逻辑陷阱

    • 原始值 false 与对象 new Boolean(false) 的不同行为:

      let bool1 = false;
      let bool2 = new Boolean(false);
      console.log(bool1 && true); // false(原值按false处理)
      console.log(bool2 && true); // true(对象按true处理)[^6]

总结核心差异

特性原始值(如 5, "text"引用值(如 {}, []
存储位置栈内存堆内存(变量保存指针地址)
复制行为独立拷贝值共享同一对象
属性动态修改不允许允许
类型检测typeof 正确区分instanceof 检测对象类型

原始包装对象特殊行为详细解释


一、原始值为什么能调用方法?

JavaScript 的基础类型(如 "hello")不是对象,但在调用方法时,会临时创建对应的包装对象,使原始值具备对象的行为:

let s = "hello";
console.log(s.substring(1)); // "ello"
  1. 实际发生了什么

    • 当调用 substring() 时,JS 引擎自动将 s 转换为 new String("hello")(String 对象)。
    • 调用完方法后,临时对象被销毁2

二、原始值与包装对象的本质区别

通过 typeof 可以直观看出两者的存储方式不同:

let a = "text";         // 原始值
let b = new String("text"); // 包装对象

console.log(typeof a);  // "string"(直接存储值)
console.log(typeof b);  // "object"(指针,指向堆内存中的对象)[^1]
  • 行为差异

    • a 无法添加属性(如 a.age = 20 无效)。
    • b 可以动态增删属性(如 b.age = 20 生效)。

三、典型陷阱:布尔值的逻辑判断

原始值和包装对象在逻辑运算中行为完全不同:

let bool1 = false;          // 原始值
let bool2 = new Boolean(false); // 包装对象(本质是对象)

console.log(bool1 && true); // false(直接按原值 false 处理)
console.log(bool2 && true); // true(对象在逻辑运算中始终被视为 true)[^1]

原因解释

  • 所有对象(包括 new Boolean(false))在逻辑运算中会被强行转为 true
  • 原始值则严格按原值处理。

四、如何记住这些差异?

特征原始值("text"包装对象(new String("text")
存储方式直接存储值存储指针,指向堆内存中的对象
方法调用临时创建包装对象直接调用
逻辑判断按实际值(如 false始终视为 true(因为是对象)
添加属性无效有效(操作真实对象)

包装对象的键(key)与值(value)详解


1. new Boolean(false) 的键与值

  • 关键点
    new Boolean(false) 实际创建的是一个 对象,内部存储了原始值 false,但其行为完全遵循对象的规则3
  • 键(keys)
    无显式可枚举属性(自身属性)。通过 Object.keys() 会返回空数组:

    let boolObj = new Boolean(false);
    console.log(Object.keys(boolObj)); // [](无直接属性)
  • 值(value)

    • 实际存储的原始值通过 valueOf() 获取:

      console.log(boolObj.valueOf()); // false(原始值)[^5]
    • 但在布尔表达式中,对象始终被视为 true

      console.log(boolObj && true); // true(包装对象的逻辑行为)[^2]

2. new String("text") 的键与值

  • 关键点
    new String("text") 会创建一个 字符串包装对象,内部存储字符串的字符序列和一个固定属性 length4
  • 键(keys)
    包含字符索引(如 0, 1, 2, 3)和 length

    let strObj = new String("text");
    console.log(Object.keys(strObj)); 
    // ["0", "1", "2", "3", "length"](不同环境中可能仅包含 "length")[^6]
  • 值(value)

    • 索引对应字符:

      console.log(strObj[0]); // "t"
      console.log(strObj[1]); // "e"
    • length 表示字符长度:

      console.log(strObj.length); // 4 [^6]
    • valueOf() 返回原始字符串:

      console.log(strObj.valueOf()); // "text"(原始值)[^5]

原理总结

类型new Boolean(false)new String("text")
本质上对象(存储 false对象(存储字符序列和 length
显式键(keys)5字符索引和 length4
实际值false(需用 valueOf()"text"(通过 valueOf()
行为差异逻辑运算中视为 true3字符和长度可直接访问4

目录:总目录
上篇文章:第三讲:JavaScript 操作符与流程控制详解

下篇文章:红宝书第五讲:函数声明与表达式小白详解


  1. 原始值和引用值的核心特性,文件 ProfessionalJavaScript5.pdf 第4章
  2. 原始值调用方法时的临时包装对象机制,文件 ProfessionalJavaScript5.pdf 第5章
  3. Boolean包装对象的逻辑行为,文件 ProfessionalJavaScript5.pdf 第5章
  4. String包装对象的length属性与字符索引,文件 ProfessionalJavaScript5.pdf 第5章
  5. 包装对象的valueOf方法,文件 ProfessionalJavaScript5.pdf 第5章

kovli
7 声望4 粉丝