从数据存储理解基本数据类型与引用数据类型

从数据存储理解数据类型

基本数据类型和引用数据类型的根本区别在于它们在内存中的存储方式。

1、数据动态存储

数据动态存储,即用内存存储数据

在JS中,主要通过这两种数据结构存储数据。用户可以直接操作栈,但不允许直接操作堆。

image-20201210143903031

1.1 谁属于基本数据类型和引用数据类型?

首先,我们声明一个变量a1,初始化为数值0;声明一个变量c,初始化为数组[1, 2, 3]。

var a1 = 0;
var c = [1, 2, 3];

问:a1是基本数据类型吗?c是引用数据类型吗?

答:不是,a1和c是变量。

数据类型是指“=”右边的,而非整个表达式。

正确的表达方式是:变量a1存储的是基本数据类型中的数值型数据0,变量c存储的是引用数据类型中的数组型数据[1, 2, 3]。

通过上方的文字,明确了 变量 和 数据 是两个不同的概念。

1.2 变量创建时内存的行为:

创建如下变量:

var a1 = 0;   // 基本数据类型-数值型
var a2 = 'this is string'; // 基本数据类型-字符串
var a3 = null; // 基本数据类型-空对象

var b = { m: 20 }; // 引用数据类型-对象,变量b存在于变量对象中,{m: 20} 作为对象存在于堆内存中
var c = [1, 2, 3]; // 引用数据类型-数组,变量c存在于变量对象中,[1, 2, 3] 作为对象存在于堆内存中

在内存中的行为是这样的:

image-20201210142019214

我们可以看出:

  • 在JS中,创建一个变量,就是在栈中申请一块内存,然后赋予这块内存名字,即变量名。以后我们就可以通过变量名找到这块内存空间。
  • 这块内存空间存储的东西,如果没有初始化,存储的是undefined;如果已经初始化,则根据其数据类型决定存储内容。
  • 对于基本数据类型,该内存空间中存储的内容即变量的值。
  • 对于引用数据类型,该内存空间中存储的内容是一个地址。通过这个地址引用存储在堆中的真正的值。

2、数据的复制

在1中我们创建了5个变量,a1、a2、a3、c、b,现在我们复制其中所有变量。

var Ca1 = a1;
var Ca2 = a2;
var Ca3 = a3;
var Cc = c;
var cB = b;

复制完后内存的状态应该是这样的:

image-20201210151256300

我们可以轻易看出,这种复制的原理就是:在栈中新申请一块内存,然后把要复制的变量的值传递给新的内存。

这样也就很好理解为什么引用型数据类型在复制后,修改新变量的值会导致原变量的值一起改变了。因为无论新老变量,存储的都不是引用数据本身,而是引用数据的地址。就好比变量中存储的只是屋子的门牌号,沿着门牌号把房子里的东西拿了,房子里的东西肯定就没了。

3、浅拷贝和深拷贝

4、理解“形参不会影响实参”

4.1 理论

首先,一个函数的运行过程:

//声明一个函数
function func(para){
	……;  //假装有内容
}
// 实际上在这个函数被运行时,效果为:
function func(trulyPara){
  var para = trulyPara;
  ……;
}

这就是实参的传参过程。

可以简略理解为:在函数内部首行进行了一次拷贝,函数内部参与运行的是拷贝后的实参,而不是实参本身。

但前边我们已经知道:修改引用数据类型的复制体,会对原数据产生影响。

那么“形参不会影响实参”这句话,就有它本身的局限性了。

这句话的正确理解应该为:如果传入函数的参数时引用数据类型,那么“形参影响实参”,如果传入函数的参数是基本数据类型,那么“形参不会影响实参”

4.2 测试

 				var arr = [70,100,82,100,92];
        var planarArr = [[70,80],[10,20]];
        var num = 1;
        function func(c){
            if(c instanceof Array){
                c[0] ++;
            }else{
                c++;
            }
        }
        func(num);  //形参为数值,形参不影响实参
        console.log(num);  //结果为1
        func(arr[1]);  //形参为数组中的某一个元素,形参不影响实参
        console.log(arr[1]);  //结果为100
        func(planarArr[1]);  //形参为二维数组中的某一个数组时,会影响实参。(此时传入的形参是数组)
        console.log(planarArr[1][0]);  //结果为11
        func(arr);  //形参为数组(引用数据类型),会影响实参
        console.log(arr[0]);  //结果为71

从测试中可知我们的推论正确,如果传入函数的参数时引用数据类型,“形参会影响实参”。

【注】一维数组的arr[1]是基本数据类型;数组中的数组,二维数组planarArr[1]是引用数据类型。


新人浅见,敬请指摘

posted on 2020-12-11 11:50  断鸿_Hua  阅读(286)  评论(0)    收藏  举报