基本类型和引用类型
数据类型
JavaScript的中的变量可能包含两种不同的数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,包括数字、字符串、布尔值、null和undefined;而引用类型值指的是可能由多个值构成的对象,包括数组、函数、正则表达式和对象本身。
在《JavaScript语言精粹》中指出:“数字、字符串和布尔值‘貌似’对象,因为他们拥有方法,但它们是不可变的。JavaScript中的对象是可变的键控集合”。这里所说的可变是指动态修改里面的值时,原始的值也会改变;而简单数据类型类不可变是指,即使是后面动态修改它的值,它的原始值并不会改变。这也就是我们下面要讨论的基本类型和引用类型的不同之处。
变量类型与数据类型一样吗?
基本类型
: 保存的就是基本类型的数据(比如:数字1,字符串‘hello lvya’,布尔值false等)和引用类型
: 保存的是地址值,这个地址值去指向某个对象。类型判断
typeof
在JavaScript中,我们可以通过typeof来判断给定变量的数据类型。typeof既可以用来检测基本数据类型,也可以用来检测引用类型,对于不同的数据类型,返回的值不同。在使用typeof进行数据类型判断是,有一下三点需要注意:
- 用
typeof
判断返回数据类型的字符串(小写)表达。比如:typeof ‘hello’
结果是string
。 -
用
typeof
来测试有以下七种输出结果:number、
string、
boolean、
object、
function、
symol、
undefined
。 因此typeof不能去判断出null
与object
,因为用typeof
去判断null
会输出object。
-
所有的任何对象,用
typeof
测试数据类型都是object
。因此,typeof
不能去判断出object
与array
。
从上面的图中,我们可以看出,typeof在检测数据类型的时候:未定义的值返回undefined、字符串返回string、数值返回number、布尔值返回boolean、对象或者null返回object,函数返回function。
instanceof
我们知道,数组、正则表达式等都属于对象,在使用typeof进行类型检测的时候,返回的结果是相同的,这个时候我们要想判断具体的类型,就需要用到instanceof方法。A instanceof B
翻译就是B的实例对象是A 吗? 判断对象的具体类型(到底是对象类型中的Object、
Array
、Function
、Date
、RegExp
的哪一个具体的类型),返回一个Boolean值:
首先判断变量是否为对象,如果是则返回true,在继续判断其具体类型。
===(全等符号)
全等符号只可以判断undefined 和 null, 因为这两种基本类型的值是唯一的,即可用全等符比较。
借调法Object.prototype.toString.call()
这种方法只可以检测出内置类型(引擎定义好的,自定义的不行),这种方法是相对而言更加安全。Object、
Date、
String、
Number、
RegExp、
Boolean
、Array、
Math、
Window
等这些内置类型。
在上面最后的例子中,使用Object.prototype.toString.call()方法来判断自定义类型时,结果显然是不正确的,此时就需要使用instanceof
复制的值
基本类型
如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,这两个值是完全独立的,可以参与任何操作而不会相互影响。
引用类型
当从一个变量向另一个变量复制引用类型的值时,同样也会复制该值到新的分配空间中,但这个复制的值其实是一个指针,指向存储在堆中的一个对象,复制后,两个变量实际上是引用同一个对象,改变其中一个变量,就会影响另一个的值,也就是上面说的可变性。
对象赋值
首先是第一个打印,需要注意后面两个值:一开始两个引用变量a
b
都指向同一个对象,而后执行a = {name: 'aaa', age: 13};
语句,就是让a
指向另一个对象{name: 'aaa', age: 13}
,a
中的内容的地址值变化了。而b
还是指向之前a
的那个对象{age: 12}
。
然后是函数fn2,用于改变形参obj的指向对象,所以执行fn2(a)语句的时候,改变的是形参,而变量a在这个过程中并没有改变执指向,也就是其地址并没有改变。反而是在函数执行完后,obj作为局部的引用变量被释放,所以有了最后一句打印报错。
传递参数
在上面我们知道了,访问变量分按值和按引用两种方式,但是,在ECMAScript中,所有的函数的参数都只能按值传递:向参数传递基本类型的值的时候,被传递的值会被复制给一个局部变量;向参数传递引用类型的值的时候,会把这个值在内存中的地址复制给一个局部变量,所以这个局部变量的变化会反映在函数的外部。
在函数addTen()中,参数num是函数的局部变量,基本类型变量count作为参数被传递给函数的时候,仅仅只是将count的值20复制给参数num,但是count和num并没有直接关系,所以在函数内部num的值加10后,函数外部的count的值依旧是20,不会被影响。
数据类型间的比较
基本数据类型间的比较
基本数据类型的数据比较遵循以下规律:
- 如果类型相同,则直接比较; 如果类型不同, 都去转成
number
类型再去比较 undefined
==null
0
和undefined
,0
和null
都不等- 如果有两个
NaN
参与比较,则总是不等的 - 只有五种转Boolean类型是
false
的:0
、Nan、
undefined
、null、
""
。其他的转Boolean值都是true
参考资料
JavaScript权威指南(第六版)
JavaScript高级程序设计(第三版)
JavaScript王者归来