红宝书第四讲:JavaScript原始值与引用值行为差异详解
资料取自《JavaScript高级程序设计(第5版)》。 查看所有教程:红宝书学习大纲
一、基本定义与存储方式
-
原始值(Primitive Values)
-
引用值(Reference Values)
- 类型:对象(
Object
)、数组(Array
)、函数(Function
)等。 - 存储方式:实际数据存储在堆内存中,变量保存的是指向堆内存的指针地址1。
- 类型:对象(
二、变量复制时的差异
-
原始值的复制:独立拷贝
- 复制后,新旧变量完全独立。
javascript代码解读复制代码
let num1 = 5; let num2 = num1; // 复制值本身 num1 = 10; console.log(num2); // 输出5(num2不受num1修改影响)[^2]
- 复制后,新旧变量完全独立。
-
引用值的复制:共享对象
- 复制的是指针地址,新旧变量指向同一个对象:
javascript代码解读复制代码
let obj1 = { name: "Alice" }; let obj2 = obj1; // 复制指针地址 obj1.name = "Bob"; console.log(obj2.name); // 输出"Bob"(通过指针修改同一对象)[^2]
- 复制的是指针地址,新旧变量指向同一个对象:
三、动态属性操作能力
-
引用值可动态增删属性
- 对象可以随时添加或删除属性:
javascript代码解读复制代码
let person = {}; // 空对象 person.name = "Alice"; // 新增属性 delete person.name; // 删除属性[^4]
- 对象可以随时添加或删除属性:
-
原始值无法添加属性
- 即使试图添加属性,也不会保留:
javascript代码解读复制代码
let name = "Charlie"; name.age = 30; // 不会报错,但无意义 console.log(name.age); // 输出undefined[^4]
- 即使试图添加属性,也不会保留:
四、类型检测与包装对象
-
类型检测工具
-
原始包装对象的特殊行为
- 原始值调用方法时临时创建对象包装器:
javascript代码解读复制代码
let s = "hello"; console.log(s.substring(1)); // 临时转换为String对象调用方法[^5]
- 包装对象与原始值的区别:
javascript代码解读复制代码
let a = "text"; let b = new String("text"); console.log(typeof a); // "string"(原始值) console.log(typeof b); // "object"(引用值)[^1]
- 原始值调用方法时临时创建对象包装器:
五、典型陷阱:原始值与包装对象的逻辑差异
- 布尔值的逻辑陷阱
- 原始值
false
与对象new Boolean(false)
的不同行为:javascript代码解读复制代码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"
)不是对象,但在调用方法时,会临时创建对应的包装对象,使原始值具备对象的行为:
javascript 代码解读复制代码let s = "hello";
console.log(s.substring(1)); // "ello"
- 实际发生了什么:
- 当调用
substring()
时,JS 引擎自动将s
转换为new String("hello")
(String 对象)。 - 调用完方法后,临时对象被销毁2。
- 当调用
二、原始值与包装对象的本质区别
通过 typeof
可以直观看出两者的存储方式不同:
javascript 代码解读复制代码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
生效)。
三、典型陷阱:布尔值的逻辑判断
原始值和包装对象在逻辑运算中行为完全不同:
javascript 代码解读复制代码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()
会返回空数组:javascript代码解读复制代码let boolObj = new Boolean(false); console.log(Object.keys(boolObj)); // [](无直接属性)
-
值(value):
- 实际存储的原始值通过
valueOf()
获取:javascript代码解读复制代码console.log(boolObj.valueOf()); // false(原始值)[^5]
- 但在布尔表达式中,对象始终被视为
true
:javascript代码解读复制代码console.log(boolObj && true); // true(包装对象的逻辑行为)[^2]
- 实际存储的原始值通过
2. new String("text")
的键与值
-
关键点:
new String("text")
会创建一个 字符串包装对象,内部存储字符串的字符序列和一个固定属性length
4。 -
键(keys):
包含字符索引(如0
,1
,2
,3
)和length
:javascript代码解读复制代码let strObj = new String("text"); console.log(Object.keys(strObj)); // ["0", "1", "2", "3", "length"](不同环境中可能仅包含 "length")[^6]
-
值(value):
- 索引对应字符:
javascript代码解读复制代码
console.log(strObj[0]); // "t" console.log(strObj[1]); // "e"
length
表示字符长度:javascript代码解读复制代码console.log(strObj.length); // 4 [^6]
valueOf()
返回原始字符串:javascript代码解读复制代码console.log(strObj.valueOf()); // "text"(原始值)[^5]
- 索引对应字符:
原理总结
类型 | new Boolean(false) | new String("text") |
---|---|---|
本质上 | 对象(存储 false ) | 对象(存储字符序列和 length ) |
显式键(keys) | 无5 | 字符索引和 length 4 |
实际值 | false (需用 valueOf() ) | "text" (通过 valueOf() ) |
行为差异 | 逻辑运算中视为 true 3 | 字符和长度可直接访问4 |
目录:总目录 上篇文章:第三讲:JavaScript 操作符与流程控制详解
Footnotes
-
原始值调用方法时的临时包装对象机制,文件 《JavaScript高级程序设计(第5版)》 第5章 ↩
-
Boolean包装对象的逻辑行为,文件 《JavaScript高级程序设计(第5版)》 第5章 ↩ ↩2
-
String包装对象的length属性与字符索引,文件 《JavaScript高级程序设计(第5版)》 第5章 ↩ ↩2 ↩3
-
包装对象的valueOf方法,文件 《JavaScript高级程序设计(第5版)》 第5章 ↩
评论记录:
回复评论: