在本教程中,您将了解 JavaScript 中两种不同类型的值,分别是原始值和引用值。
JavaScript 有两种不同类型的值:
- 原始值
- 引用值
原始值是原子数据,而引用值是可能包含多个值的对象。
栈和堆内存
当您声明变量时,JavaScript 引擎会在两个内存位置为它们分配内存:堆栈 Stack 和堆 heap。
静态数据是在编译时大小固定的数据。静态数据包括:
由于静态数据的大小是不变的,JavaScript 引擎会为静态数据分配固定大小的内存空间,并将其存储在栈。
例如,下面语句声明两个变量并将它们的值初始化为字符串和数字:
let name = 'John';
let age = 25;
因为 name
和 age
是原始值,JavaScript 引擎将这些变量存储在堆栈中,如下图所示:
请注意,字符串在许多编程语言是对象,包括 Java 和 C#。然而,字符串是 JavaScript 的原始值。
与堆栈不同,JavaScript 将对象和函数存储在堆。JavaScript 引擎不会为这些对象分配固定数量的内存。相反,它会根据需要分配更多空间。
以下示例定义了 name
、age
和 person
变量:
let name = 'John';
let age = 25;
let person = {
name: 'John',
age: 25,
};
在内部,JavaScript 引擎分配内存如下图所示:
在此图中,JavaScript 在堆栈上为三个变量、age
和 name
以及 person
分配内存。
JavaScript 引擎在堆内存上创建一个新对象。此外,它将堆栈内存中的 person
变量链接到堆内存中的对象。因此,我们说 person
变量是对象的引用。
动态属性
引用值允许您随时添加、更改或删除属性。例如:
let person = {
name: 'John',
age: 25,
};
// 添加 ssn 属性
person.ssn = '123-45-6789';
// 修改 name 属性
person.name = 'John Doe';
// 删除 age 属性
delete person.age;
console.log(person);
{ name: 'John Doe', ssn: '123-45-6789' }
与引用值不同,原始值不能具有属性。这意味着您不能将属性添加到原始值。
但 JavaScript 允许您将属性添加到原始值。然而,它不会产生任何效果。
let name = 'John';
name.alias = 'Knight';
console.log(name.alias); // undefined
在此示例中,我们将 alias
属性添加到 name
原始值。但是当我们通过原始值 name
访问 alias
属性时,它返回 undefined
。
复制值
当您将一个变量的原始值分配给另一个变量时,JavaScript 引擎会创建值的副本并将其分配给变量。例如:
let age = 25;
let newAge = age;
在这个例子中:
- 首先,声明一个新变量
age
并用值25
初始化它。 - 其次,声明另一个变量
newAge
并将newAge
变量的值分配给age
。
在幕后,JavaScript 引擎创建原始值的副本 25
并将其分配给 newAge
变量。下图说明了赋值后的栈内存。
在堆栈内存中,newAge
和 age
是单独的变量。如果你改变一个变量的值,它不会影响另一个。
let age = 25;
let newAge = age;
newAge = newAge + 1;
console.log(age, newAge);
当您将一个变量的引用值赋给另一个变量时,JavaScript 引擎会创建一个引用,以便两个变量都引用堆内存中的同一个对象。
这意味着如果你改变一个变量,它会影响另一个。例如:
let age = 25;
let newAge = age;
newAge = newAge + 1;
console.log(age, newAge);
首先,声明一个 person
变量并用一个具有两个属性 name
和 age
的对象初始化它的值。
第二,将 person
变量赋值给 member
变量。在内存中,两个变量都引用同一个对象,如下图所示:
第三、通过 member
变量改变 age
对象的属性:
由于 person
和 member
变量都引用同一个对象,因此通过 member
变量修改对象也会反映在 person
变量中。
结论
- Javascript 有两种类型的值:原始值和引用值。
- 您可以向引用值添加、更改或删除属性,而不能对原始值执行此操作。
- 将原始值从一个变量复制到另一个变量会创建一个单独的值副本。这意味着改变一个变量的值不会影响另一个。
- 将引用从一个变量赋值到另一个变量会创建一个引用,以便两个变量引用同一对象。这意味着通过一个变量修改对象后会反映在另一个变量中。