在本教程中,您将了解 JavaScript 中两种不同类型的值,分别是原始值和引用值。

JavaScript 有两种不同类型的值:

  • 原始值
  • 引用值

原始值是原子数据,而引用值是可能包含多个值的对象。

栈和堆内存

当您声明变量时,JavaScript 引擎会在两个内存位置为它们分配内存:堆栈 Stack 和堆 heap。

静态数据是在编译时大小固定的数据。静态数据包括:

由于静态数据的大小是不变的,JavaScript 引擎会为静态数据分配固定大小的内存空间,并将其存储在栈。

例如,下面语句声明两个变量并将它们的值初始化为字符串和数字:

let name = 'John'; 
let age = 25;

因为 nameage 是原始值,JavaScript 引擎将这些变量存储在堆栈中,如下图所示:

JavaScript 栈内存

请注意,字符串在许多编程语言是对象,包括 Java 和 C#。然而,字符串是 JavaScript 的原始值。

与堆栈不同,JavaScript 将对象和函数存储在堆。JavaScript 引擎不会为这些对象分配固定数量的内存。相反,它会根据需要分配更多空间。

以下示例定义了 nameageperson 变量:

let name = 'John';
let age = 25;

let person = {
  name: 'John',
  age: 25,
};

在内部,JavaScript 引擎分配内存如下图所示:

JavaScript 堆 内存

在此图中,JavaScript 在堆栈上为三个变量、agename 以及 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 变量。下图说明了赋值后的栈内存。

JavaScript 复制原始值

在堆栈内存中,newAgeage 是单独的变量。如果你改变一个变量的值,它不会影响另一个。

let age = 25;
let newAge = age;

newAge = newAge + 1;
console.log(age, newAge);
JavaScript 改变原始值

当您将一个变量的引用值赋给另一个变量时,JavaScript 引擎会创建一个引用,以便两个变量都引用堆内存中的同一个对象。

这意味着如果你改变一个变量,它会影响另一个。例如:

let age = 25;
let newAge = age;

newAge = newAge + 1;
console.log(age, newAge);

首先,声明一个 person 变量并用一个具有两个属性 nameage 的对象初始化它的值。

第二,将 person 变量赋值给 member 变量。在内存中,两个变量都引用同一个对象,如下图所示:

JavaScript 复制引用值

第三、通过 member 变量改变 age 对象的属性:

JavaScript 改变引用值

由于 personmember 变量都引用同一个对象,因此通过 member 变量修改对象也会反映在 person 变量中。

结论

  • Javascript 有两种类型的值:原始值和引用值。
  • 您可以向引用值添加、更改或删除属性,而不能对原始值执行此操作。
  • 将原始值从一个变量复制到另一个变量会创建一个单独的值副本。这意味着改变一个变量的值不会影响另一个。
  • 将引用从一个变量赋值到另一个变量会创建一个引用,以便两个变量引用同一对象。这意味着通过一个变量修改对象后会反映在另一个变量中。