js的数据类型主要分为两种——引用类型和值类型。其中,值类型都不是对象包括undefined、number、string、bollean这,引用类型都是对象主要包括函数、数组、object或json、null、内置对象。那么引用类型和值类型又有什么区别呢?我们先来看下面的一个例子
var num1;//这个时候不进行内存分配
var num3=9//分配内存
var num4=num3;
console.log(num3)
console.log(num4)
num3=33333
num4=44444
console.log(num3);
console.log(num4)
输出结果为:
这是一个值类型number的例子,当申请一个变量num1不赋值的时候系统是没有进行内存分配的,当申请一个变量num3并赋值为9的时候系统才进行内存分配,然后再定义一个num4并且把num3的值赋值给num4,此时输出num3和num4值都为9。输出后改变num3和num4的赋值再次输出此时num3和num4的值不同。从这个例子中我们可以看出num3和num4彼此有独立的空间互不影响,从此我们可以得出值类型拥有这个特点。
那么引用类型又有什么特点呢?我们来看例子二
//数组
var arr1=['你好','hello']
var arr2=arr1;//本质是把arr1里面的地址拷贝给了arr2
//引用类型其实是指向的同一个地址,也就是操作的其实是同一个位置
//arr1和arr2存的是指向['你好','hello']的地址
console.log(arr1[0]);
console.log(arr2[0]);
//修改数组1值
arr1[0]='hi'
console.log('数组1的值:'+arr1[0]);
console.log('数组2的值:'+arr2[0]);
arr2[0]='yes'
console.log('数组1的值:'+arr1[0]);
console.log('数组2的值:'+arr2[0]);
输出结果为:
这是一个引用类型数组的例子,我们申请一个变量arr1并且赋值为一个数组。再申请一个变量arr2同时把arr1的值赋值给arr2,此时输出arr1[0]和arr2[0]都为’你好’。然后我们再修改数组arr1里面索引为0值为’h1’再次输出发现arr1[0]与arr2[0]的值都一样为’h1’,使用控制变量法我们最后修改arr2[0]的赋值为’yes’再次输出发现arr1[0]与arr2[0]的值都一样为’yes’。这表明arr1和arr2彼此没有独立的空间并且相互影响。那么arr1与arr2之间到底是什么关系呢?我们看下面的图
我们使用计算机组成原理的知识来看这个问题,当我们var arr1=[‘你好’,‘hello’]时,可以如图所示理解为在内存空间2中1001地址上存在了[‘你好’,‘hello’]。而在arr1中存下了存着[‘你好’,‘hello’]的地址1001。当我们进行var arr2=arr1时本质上是把arr1里面存的地址1001拷贝给了arr2,所以现在arr2里面存的也是地址1001也就是说现在arr1和arr2里存的都是指向[‘你好’,‘hello’]的地址1001。当我们进行arr1[0]='hi’时系统会找到arr1里存的地址上的值并且修改它为[‘hi’,‘hello’],所以此时输出arr1[0]与arr2[0]的值就是一样的了。同理,后面修改arr2[0]的值为’yes’时,arr1和arr2输出的值也是一样的。
当我们用数据结构的眼光看这个问题时我们可以认为引用类型数组arr1和arr2是指针,指向存着[‘你好’,‘hello’]这个内存空间。所以后面的修改都是通过指针找到这片区域进行修改。
总结值类型和引用类型的区别
1.值类型
- 占用内存固定,保存在栈中
- 保存与复制的是值的本身,当把一个值赋给另一个值后他们是彼此独立的
2.引用类型
- 占用内存不固定,保存在堆中
- 当把一个值赋给另一个值其实只是拷贝了地址,对象赋值就当做指针看待