数据类型
我们都知道,数据类型分为简单数据类型(string,number,boolean,以及两种空【undefined,null】
),和复杂数据类型(object,array等
)
简单数据类型(值类型)
细说简单数据类型的话,我们要记住一个特殊的情况,那就是null
,这个值类型,如果使用typeof()
检测一下的话,他的类型是对象object,这个是一个bug,并且没有去修复。那么你可能要问了,那他的使用场景呢?eg:如果我们要创建一个对象,但是又没想好,给他写哪些属性值的时候,那就直接让一个对象名等于null。
聊完特殊情况那么看看简单数据类型是如何存储的吧:
在此之前我们得先知道栈和堆的概念;栈和堆都是内存空间,但是存储的东西是有差别的。
-
栈里面存的是简单数据类型的值,以及复杂数据类型的地址值;
-
堆里面存的是复杂数据类型的值。
1> 接下来看简单数据类型如何存储的。
假如说我们定义一个变量num,存储值为:123 ,也就是var num = 123;
,我们上面说到,栈是存储简单数据类型的…那么看如下图演示…(看图更加形象)
上图刚刚保存的太快,忘了写画步骤了,在这里补上…
- 先声明num
- 在栈空间开辟值为123的空间
- 变量num指向栈中的123空间
简单数据类型如何传参
我们给设置个场景:
function fn(a) {
a++;
alert(a); // 值为多少?
}
var x = 10;
fn(x);
alert(x); // 值为多少?
我们把这段代码拿到我们的绘图软件中分析。
过程解释:
最上面是一个函数我们不用看,因为函数不调用是不会执行的。那么往下分析var x = 10 ;
那么就在栈中开辟一个空间储存10,然后x指向10,下面是调用了fn(x),由于x的值我们是知道的,相当于给函数传了一个实参为10的数字,那么此时形参a也就等于10,那么在栈中也就开辟了一个新的空间存储a的值,很显然函数内部让a自增了,那么他的结果也就重新改变了一次,为:a=10+1=11,此时已经算出fn(x)的值为11;接下来就是最后一行代码alert(x)
,由于x的指向是10并没有发生改变,因此输出结果为10;
第一个值显然为:11 (此时是调用的函数,值是看a的值)
第二个值显然为:10 (此时是输出原来的x指向,是不变的,依旧为10)
复杂数据类型
上面我们从简单数据类型是怎么在栈中存储的,以及怎么传参访问,那么我们复杂数据类型也有自己存储机制,以及如何传参…
怎么存储:
复杂数据类型的存储用到了栈和堆,但是结果是存储在堆中的,那么栈中存什么呢?存堆中值的地址,这个地址是十六进制数码,谁指向十六进制数码呢?那就是复杂数据类型的变量名。也就是说我们创建了一个 var arr = ['a', 'b','c'];
我们想访问数组,那么就分为三个步骤,arr
指向栈中的十六进制地址,地址再指向堆中的复杂数据类型的值。
图示:
首先声明一个复杂类型变量arr
,然后再栈中开辟一个空间存储堆中值的地址,最后变量指向地址,地址指向值.
此时和普通数据类型相比,一个存在堆中,一个存在栈中,并且存在堆中的复杂数据类型比简单数据类型的存储多了一步(在栈中开辟一个空间地址)…
那么复杂数据类型的传参怎么分析呢?
以以下代码为例:
<script>
function Person(name) {
this.name = name;
}
function f1(x) {
alert(x.name); // 此时输出的是什么? 靓仔
x.name = '旺仔';
alert(x.name); // 此时输出的是? 靓仔
}
var p = new Person('靓仔');
alert(p.name); // 此时输出的是? 旺仔
f1(p);
alert(p.name); // 此时输出的是? 旺仔
</script>
代码分析:
把复杂类型作为参数传递到函数中的时候,想当于让他赋值给了形参,但是赋值的并不是值,而是地址,想当于在栈中重新开辟了一个一模一样的地址,让形参指向该地址,他们两个地址因为相同,因此都指向堆中的一个值。
下面我们分析代码:上面是一个构造函数和一个普通函数,老样子函数不调用也就不执行,我们先不看;继续往下走,下面是把构造函数new
出来,并且给它传递了一个name参数为靓仔,那么此时堆中的情况就如上图3.所示,里面的name = ‘‘靓仔’’;那么继续往下走,此时输出了实例化的p.name
那么显然此时的name 为 靓仔,继续往下看;调用了函数fn§,此时相当于调用了第二个函数,并且把new出来的对象作为实参传给了函数fn,那么此时f1中的形参x也就等于了对象p,此时给形参x在栈中开辟一个地址,很显然地址与之前的一样,既然地址一样,那么也就指向了同一个堆中的值;我们继续看函数体,此时调用了x.name
很显然,既然指向的地址都一样,那么值也一样,我们也就可以得出,此时的x.name
还是等于靓仔;接下来我们看到给形参更换了值为:x.name = "旺仔"
;此时看下图:
我们发现,此时堆中的值是彻底改变了,因为两个变量指向的都是一个值,通过任何一个改变,另外一个指向的值也就随着改变,这个与简单数据类型是不一样的、这一点可以作为区分点。
那么从此刻开始不管调佣x.name
也好,还是p.name
也好,值都为旺仔而不再是靓仔了.
输出结果为: 靓仔 靓仔 旺仔 旺仔
tips: 看清楚指向,开辟好空间。切记形参也是一个变量,在传参的时候也要给他开辟空间噢…
不断复盘,不断优秀,让自己成为镜子里想成为的那个人.关注三连,持续更新~~~