JavaScript 原始值与引用值深度解析:内存、比较与赋值机制

宋时安
宋时安
发布时间:2026-10-15| 5人浏览过
原创

JavaScript 中的数据类型分为原始值和引用值两大类,它们在内存分配、访问方式、比较逻辑及赋值行为上存在本质区别。原始值如字符串、数字等存储在栈区,按值复制;而对象存储在堆区,变量保存的是指向堆内存的引用地址。理解这一机制是掌握对象拷贝、参数传递及比较运算符行为的基础。

JavaScript 数据类型的分类与定义

在 JavaScript 中,所有值均可归纳为两大类别:基本类型(Basic Type)与引用类型(Reference Type)。这种分类不仅影响代码逻辑,更直接决定了数据在计算机内存中的存储方式。

第1步:识别基本数据类型

基本数据类型又被称为原始值(Primitive Values),它们是构成程序的最底层单元,不可再细分。ES6 规范定义了以下 6 种基本类型:

  • string:字符串
  • number:数值
  • boolean:布尔值
  • null:空值
  • undefined:未定义
  • symbol:符号(ES6 新增,表示唯一标识符)

这些类型的值大小固定,因此系统能预先分配固定大小的内存空间,通常位于栈内存(Stack)中。

第2步:识别引用数据类型

引用数据类型主要指 object 类型,包括普通对象 {}、数组 []、函数 function 等。由于对象可以包含任意数量的属性和方法,其内存占用大小在编译时无法确定,因此这类复杂数据存储在堆内存(Heap)中。变量的内存地址则存放在栈中,指向堆中的实际数据。

内存模型:栈区与堆区的运作机制

理解原始值与引用值的差异,关键在于理解 JavaScript 引擎如何管理内存。我们可以将栈区想象为一排整齐的乒乓球盒子,每个盒子大小相同,存放简单数据;而堆区则像一个巨大的仓库,用于存放形状各异且大小不一的对象数据。

原始值的栈式存储

当声明一个原始值变量时,栈内存中会直接开辟空间并存储该值。

var str = "Hello World";
var num = 10;
var bol = true;
var myNull = null;
var undef = undefined;

此处需注意 typeof null 的历史遗留问题。执行 typeof myNull 返回 "object",这是因为 JavaScript 最初版本采用二进制前三位区分类型,全 0 被判定为 object。这是一个著名的 Bug,因修复成本过高而被保留至今。尽管 typeof 显示为 object,但在比较逻辑 null == undefined 中,两者会被视为等同的“无”。

引用值的堆栈关联

引用值的赋值过程涉及两个步骤:首先在堆内存中创建对象,然后在栈内存中创建一个指针(地址)指向该堆对象。

// 在堆内存中创建数组 [1, 2, 3] 和对象 {m: 20}
var c = [1, 2, 3];
var d = { m: 20 }; // c 和 d 的栈内变量仅存储指向堆中数据的地址

核心差异对比:访问、比较与赋值

原始值与引用值在实际编程中表现出截然不同的行为,主要体现在访问方式、比较规则和属性操作上。

1. 访问与赋值方式

  • 原始值:按值访问(Pass by Value)
    赋值操作会在栈中创建一个完全独立的新副本。修改原变量不会影响新变量。
var a = 10;
var b = a;       // b 获得了 a 的值副本 10
b = 5;
console.log(a);  // 输出 10,a 不受影响
  • 引用值:按引用访问(Pass by Reference)
    赋值操作是将栈中的地址指针复制到新变量中。两个变量指向堆中的同一个对象,修改其中一个会反映在另一个上。
var obj = { name: "zhangsan" };
var obj2 = obj;      // obj2 获得指向同一堆对象的地址
obj.name = "lisi";
console.log(obj2.name); // 输出 "lisi",因为指向同一内存地址

2. 比较逻辑

  • 原始值比较:比较的是实际的值。只要内容相同,即认为相等。
var x = 10;
var y = 10;
console.log(x === y); // true,值相同
  • 引用值比较:比较的是内存地址(引用)。即使两个对象内容完全一致,若它们存储在堆的不同位置,则不相等。
var o1 = { val: 1 };
var o2 = { val: 1 };
console.log(o1 === o2); // false,尽管结构相同,但指向不同的堆内存地址

var o3 = o1;
console.log(o3 === o1); // true,指向同一地址

3. 动态属性操作

原始值是 immutable(不可变)的简单值,不能为其添加自定义属性。尝试这样做不会报错,但属性会被忽略或转换为包装对象后丢弃(取决于严格模式或具体实现环境)。

var s = "test";
s.prop = true;
console.log(s.prop); // undefined

而对象是 mutable(可变)的容器,支持动态添加、修改和删除属性。

var o = {};
o.prop = true;
console.log(o.prop); // true

常见误区与最佳实践

明确原始值与引用值的界限,能有效避免常见的 Bug,特别是在处理复杂数据结构时。

  1. 函数参数的传参陷阱:
    向函数传递原始值时,函数内部修改参数不会影响外部变量。但如果传递的是对象,函数内部通过参数名修改对象属性,会影响到外部原始对象(浅层影响)。
  2. 避免意外共享状态:
    当需要克隆一个对象但不希望相互影响时,简单的赋值 b = a 会导致共享引用。此时应使用展开语法 {...a}、Object.assign({}, a) 或深拷贝库来创建新的独立对象。
  3. 关于 null 与 undefined 的使用:
    null 是一个表示“无对象”的空值,需手动赋值,常用于清空对象引用。undefined 是变量声明但未初始化时的默认值,由系统自动赋予。在 API 设计中,用 null 表示有意为空,用 undefined 表示缺失或未定义,有助于提升代码可读性。

以上就是对 JavaScript 中原始值和引用值的详细内容解析,更多关于 JavaScript 数据类型与内存管理的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。