1. 值类型
ECMA变量有两种不同的类型:原始值和引用值。原始值可以理解成Java里的基本数据类型,其值存在栈中。有6种原始类型:Null, Undefined, Boolean, Number, String, Symobl。其中Null和Undefined这两种类型各只有一个值,分别是null
和undefined
。
当使用var
或者let
声明了变量但没有初始化时,就相当于给变量赋予了undefined
值。对于未初始化的变量和未声明的变量使用typeof
,都会返回undefined
。那么为什么未声明的变量也会返回undefined
呢?在《JavaScript高级程序设计》中解释的是:
虽然严格上来讲这两个变量存在根本性差异,但它们都无法执行实际操作。
因此这本书建议我们在声明变量的同时进行初始化。这样当typeof
返回undefined
时,我们就知道是给定的变量未声明,而不是声明了但未初始化。
引用值就是对象,它把数据内容存放在堆中,而把堆的地址存放在栈中。可以理解为存在变量处的是一个指针,指向存储对象的内存处。常见的引用类型有Object、Array以及Function(没错,其实函数也是一种引用类型)。ES6引进的新引用类型有Map、WeakMap、Set、WeakSet。
值得注意的是:
1. null
值表示一个空对象指针,用typeof
判断null
会返回object
,但是null
并不是对象,而是基本数据类型的一种。undefined
值是由null
值派生而来的。因此用等于操作符==
比较它们会返回true
,但它们的用途是完全不一样的。在定义将来要保存对象值的变量时,建议用null
来初始化。那我们如何判断一个变量是不是null
呢?应该使用===
来判断,为什么不是==
呢,因为三等号操作符在比较的时候不会将变量强制转换为另一种类型。这样三等号就不会认为null
和undefined
相等。
2. Boolean、Number、String其实是三种特殊的引用类型,叫做原始值包装类型。这些类型具有引用类型的特点和原始类型对应的特殊行为。对于这三种原始值,每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型对象。
3. 如果创建一个带有空位的数组,数组的值将为undefined
。鉴于undefined
也是一种值类型,[undefined]
数组的长度为1。
2. 传参方式
我们都知道JS对值的访问方式有两种,保存原始值的变量是按值访问的,而保存引用值的对象是按引用访问的。但是JS的传参方式其实只有一种,就是按值传递。当我们传递原始值时,我们将原始值复制一份到另一个内存空间中。当我们传递引用值时,实际上我们传递的也是引用值的副本,即我们将这个地址复制了一份放到了另一个内存空间中。这样通过这个地址,我可以访问和修改该引用值的属性,但如果我new一个新的对象,我原来这个对象并不会被改变。