JS变量的基本类型和引用类型及内存机制详解
作者:秋了秋 发表时间:2015年12月19日
在javascript中,所有的变量可用基本类型和引用类型区分开来,而运行javascript时是在内存中运行,此时内存会被划分为栈内存和堆内存,栈内存是放基本类型的值,这些值分别存在所分配的物理位置,占据着固定大小的空间(小片段),而堆内存是放引用类型的对象,注意这里并不是值而是对象,是一个指针,这个指针指向内存中的另一个位置,这个位置存放着这个对象,这个对象占据着不固定大小的空间,除了占据堆内存,引用类型还有一部分保存在栈内存中,那就是它的地址,访问这个变量的时候先从栈内存中读取它的地址,通过地址找到存放在堆内存中的值,就好比栈内存存放一个网页链接,我们通过访问这个链接打开存在堆内存中的数据(即网页实体)。
如何区分基本类型和引用类型? 基本类型,就那么几种:Number(数字)、String(字符串)、Boolean(布尔值)、undefined(未定义)、null(空) 而引用类型则是所有的Object对象。 如果不确定某个变量的类型,可通过typeof查看这个变量的类型。
我们可以用一张图来诠释内存与变量的基本关系:
基本类型变量,每定义一个变量,就会在栈内存中开辟一个存放这个变量的空间,如a=b="秋叶";这时候栈内存中就会存放着a="秋叶";b="秋叶";程序访问变量的时候,直接读取对应的值。而引用类型的变量,如果有两个不同的变量指向同一个对象,则这个对象是唯一存在堆内存的。如a=b=function(){this.name='秋叶';}唯一不同的是存在栈内存中的地址;通过栈内存中的一个地址修改了对象的值,则另外一个地址的对象也会跟着变。因为它们是指向关系,指向同一个引用对象。就好比两个人合租,其中一个人下班回家把一只灯泡打烂了,另一个人下班回家走进房间也会看到灯泡烂了,他们是公用关系。
很多时候我们都能看到javascript中经常会有abc.name这种.后面跟一个属性或者方法的用法只有引用类型才具备,基本类型是不能这样用的,比如说定义一个变量a="秋叶";这是一个基本类型,我们不能随便给它加个a.xxx的这种定义或者访问的方法,这是一种错误的写法。只有Object才具备这种写法,如var a=new String();这时a被new了一下就变成了一个对象,然后可以直接给它添加属性或者方法a.xxx,这是合法的。
有的人会发现字符串不是有这种写法吗:var a="我是秋叶";a.substring(2);
这里又不得不说一下基本类型中还有一种类型叫"基本包装类型",像刚刚看到的字符串就是基本包装类型的一种,除了String,还有Boolean和Number也是基本包装类型,他们都有系统给的方法和属性。这种基本类型可以调用系统的属性和方法,但是不可以给它定义属性和方法,a.substring就是调用了window(系统)下的substring方法。