原始值 引用值

ECMAScript变量可以包含两种不同类型的数据:原始值和引用值。

原始值( primitive value)就是最简单的数据,引用值( reference value)则是由多个值构成的对象。

访问方式

在把一个值赋给变量时,JavaScript引擎必须确定这个值是原始值还是引用值。

  • 6种原始值:Undefined、Null、Boolean、Number、string和symbol。保存原始值的变量是按值(byvalue )访问的,因为我们操作的就是存储在变量中的实际值。
  • 引用值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用( reference)而非实际的对象本身。为此,保存引用值的变量是按引用( by reference)访问的。

动态属性

对于引用值而言,可以随时添加、修改、删除其属性和方法。
原始值不能有属性,尽管在尝试给原始值添加属性不会报错。
只有引用值可以动态添加后面可以使用的属性。

注意,原始类型的初始化可以只使用原始字面量形式。
如果使用的是new关键字,则JavaScript会创建一个object类型的实例,但其行为类似原始值。
下面来看看这两种初始化方式的差异:

  1. let name1 = "Nicholas" ;
  2. let name2 = new string ( "Matt " ) ;
  3. name1.age = 27 ;
  4. name2.age = 26 ;
  5. console.log (name1.age ) ;// undefined
  6. console.log ( name2.age) ;//26
  7. console.log (typeof name1) ; // string
  8. console.log ( typeof name2) ; //object

复制值

除了存储方式不同,原始值和引用值在通过变量复制时也有所不同。
在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置。请看下面的例子:

  1. let numl = 5;
  2. let num2 = numl;

这里,num1包含数值5。当把num2初始化为num1时,num2也会得到数值5。这个值跟存储在num1中的5是完全独立的,因为它是那个值的副本
这两个变量可以独立使用,互不干扰。这个过程如图4-1所示。
image.png
在把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。
区别在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象。
操作完成后,两个变量实际上指向同一个对象,因此一个对象上面的变化会在另一个对象上反映出来,如下面的例子所示:
image.png

传递参数

ECMAScript中所有函数的参数都是按值传递的。这意味着函数外的值会被复制到函数内部的参数中,就像从一个变量复制到另一个变量一样。
如果是原始值,那么就跟原始值变量的复制一样,如果是引用值,那么就跟引用值变量的复制一样。
变量有按值和按引用访问,而传参则只有按值传递。
在按值传递参数时,值会被复制到一个局部变量(即一个命名参数,或者用ECMAScript的话说,就是arguments对象中的一个槽位)。在按引用传递参数时,值在内存中的位置会被保存在一个局部变量,这意味着对本地变量的修改会反映到函数外部。(这在ECMASeript中是不可能的。)来看下面这个例子:

:::warning 原始值与引用值的区别:

  • 原始值存储在中,引用值存储在
  • 原始值是以值的拷贝方式进行赋值,值是不可变的;
  • 引用值是以引用的拷贝方式进行赋值,值是可变的
  • 原始值的比较是值的比较,引用值的比较是引用的比较(比较引用的是否为同一对象) :::