JavaScript 中的数据类型可以分为两种:原始类型和引用类型。

    原始类型(Primitive types)包括:

    1. Number
    2. String
    3. Boolean
    4. Null
    5. Undefined
    6. Symbol (ES6新增)
    7. BigInt (ES2020新增)

    这些类型的值是直接存储在变量访问的位置(栈内存)中的,即它们的值在内存中是以副本形式存在。每个变量都有自己的内存空间,它们的值互不影响。当你对一个原始类型的变量进行操作,操作的实际上是这个变量所保存的实际的值。

    引用类型(Reference types)包括:

    1. Object
    2. Array
    3. Function

    引用类型的值(对象、数组、函数等)是保存在堆内存中的,变量实际上保存的是一个指针,这个指针指向堆内存中的位置。当你对引用类型的变量进行操作时,操作的实际上是其引用的对象在堆内存中的值。

    这就导致了原始类型和引用类型在赋值和比较操作中的差异。

    1. 原始类型的赋值是值的复制,而引用类型的赋值是引用(指针)的复制,一个对象的改变会影响到所有引用或指向它的变量
    2. 对于原始类型的比较,是直接比较其值是否相等;对于引用类型的比较,是比较其引用的地址是否一样,即是否指向堆内存中的同一个对象。

    当你创建一个对象、数组或函数,实际上创建的是一个引用,这个引用指向了内存中的一块区域,这块区域存储着真正的对象、数组或函数的值。

    假设我们有以下代码:

    1. var obj1 = { value: 10 };
    2. var obj2 = obj1;
    3. obj2.value = 20;
    4. console.log(obj1.value); // 输出:20

    在这个例子中,我们首先创建了一个对象obj1,然后我们将obj1的引用赋值给了obj2。当我们通过obj2修改对象的值时,因为obj1obj2都是引用同一块内存区域,所以obj1的值也会被改变。

    js 引用类型和原始类型 - 图1

    但是这种引用的特性并不适用于基础数据类型(如 Number、String、Boolean、null、undefined、Symbol)。这些类型的数据在赋值的时候,实际上是直接复制了一份新的数据,对新的数据做修改不会影响到原始的数据。例如:

    1. var num1 = 10;
    2. var num2 = num1;
    3. num2 = 20;
    4. console.log(num1); // 输出:10

    在这个例子中,num1的值并没有因为num2的修改而改变,这就说明了基础数据类型在赋值操作时其实是进行了一次数据的复制。

    js 引用类型和原始类型 - 图2