基本类型和引用类型

数据类型

JavaScript的中的变量可能包含两种不同的数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,包括数字、字符串、布尔值、null和undefined;而引用类型值指的是可能由多个值构成的对象,包括数组、函数、正则表达式和对象本身。

在《JavaScript语言精粹》中指出:“数字、字符串和布尔值‘貌似’对象,因为他们拥有方法,但它们是不可变的。JavaScript中的对象是可变的键控集合”。这里所说的可变是指动态修改里面的值时,原始的值也会改变;而简单数据类型类不可变是指,即使是后面动态修改它的值,它的原始值并不会改变。这也就是我们下面要讨论的基本类型和引用类型的不同之处。

变量类型与数据类型一样吗?

数据的类型:包含基本数据类型和对象类型。
变量的类型(实则是变量内存值的类型) JS弱类型语言,变量本身是无类型的。包含基本类型: 保存的就是基本类型的数据(比如:数字1,字符串‘hello lvya’,布尔值false等)和引用类型: 保存的是地址值,这个地址值去指向某个对象。

类型判断

typeof

在JavaScript中,我们可以通过typeof来判断给定变量的数据类型。typeof既可以用来检测基本数据类型,也可以用来检测引用类型,对于不同的数据类型,返回的值不同。在使用typeof进行数据类型判断是,有一下三点需要注意:

  1. typeof判断返回数据类型的字符串(小写)表达。比如:typeof ‘hello’ 结果是 string
  2. typeof来测试有以下七种输出结果:number、string、boolean、object、function、symol、undefined。 因此typeof不能去判断出nullobject,因为用typeof去判断null会输出object。
  3. 所有的任何对象,用typeof测试数据类型都是object。因此,typeof不能去判断出objectarray

从上面的图中,我们可以看出,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,不会被影响。

数据类型间的比较

基本数据类型间的比较

基本数据类型的数据比较遵循以下规律:

  1. 如果类型相同,则直接比较; 如果类型不同, 都去转成number类型再去比较
  2. undefined == null
  3. 0undefined0null都不等
  4. 如果有两个 NaN参与比较,则总是不等的
  5. 只有五种转Boolean类型是false的:0 、Nan、 undefined 、null、""。其他的转Boolean值都是true

  

参考资料

JavaScript权威指南(第六版)

JavaScript高级程序设计(第三版)

JavaScript王者归来

posted on 2018-05-07 22:00  紅葉  阅读(1825)  评论(0编辑  收藏  举报