js基本类型与引用类型

时间:2023-02-04 15:45:42

1.基本类型:Underfined ,Null, Boolean,Number,String

2.引用类型: Object

首先了解一个概念:栈内存与堆内存---这是两种不同的内存分配方法

一般代码逻辑,简单变量,结构体都是放在栈中;而对象,以及被装箱的数据放在堆中


栈内存中存放地址指向堆内存中的对象

基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象

基本类型在内存中分别占有固定大小的空间,他们的值保存在栈空间中,我们通过按值访问

引用类型:值的大小不固定,栈内存中存放地址指向堆内存中的对象,是按引用访问的。栈内存中存放的只是该对象的访问地址

在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把他们保存在栈内存中。但内存地址大小是固定的,因此可以将内存地址保存在栈内存中。这样,当查询引用类型的变量时,先从栈中读取内存地址,然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。

当我们看到一个变量类型是已知的,就分配在栈里面,比如INT,Double等,其它未知的类型,比如自定义类型,因为系统不知道需要多大,所以程序自己申请,这样就分配在堆里面。基本类型大小固定,引用类型大小不固定,分开存放使得程序运行占有内存最小。

栈内存:存放基本类型。堆内存:存放引用类型(在栈内存中存放一个基本类型值保存对象在堆内存中的地址,用于引用这个对象)

4.基本类型在当前执行环境结束时销毁,而引用类型不会随执行环境结束而销毁,只有当所有引用它的变量不存在是这个对象才被垃圾回收机制回收。


基本类型有一下几个特点:

1.基本类型的值是不可变的

任何方法都无法改变一个基本类型的值,比如一个字符串:

```

var name  = 'hello';

name.toUpperCase();  //输出HELLO

console.log(name);   //输出 hello

会发现原始的name并未发生改变,而是调用了toUpperCase()方法后返回的是一个新的字符串

再来个例子:

var person = 'Mary';

person.age = 22;

person.method = function(){};

console.log(person.age); //underfined

console.log(person.method);//underfined

通过上面代码可知,我们不能给基本类型添加属性与方法,再次说明基本类型是不可变的


2.基本类型的比较是值的比较

只有他们的值相等的时候他们才相等

var a =1;

var b = true;

console.log(a==b);  //true

有这个疑问,这就得了解一下类型转换和 == 运算符的知识了,也就是说在用==比较两个不同类型的变量是会进行一些类型转换,像上面的比较先会把true转换为1,再和数字1笔记,结果就是true了。这是当比较两个值的类型不同的时候的时候==运算符会进行类型转换,但是当两个值的类型相同的时候,即使是 == 也相当于 ===。

3.基本类型的变量是存放在栈区的(栈区指内存里的栈内存)


引用类型:除了基本类型就是引用类型,也就是说对象。对象是属性与方法的集合

也就是说引用类型可以拥有属性与方法,属性又可以包含基本类型与引用类型。来看看引用类型的一些基本特性:

1.引用类型的值是可变的

我们可以为引用类型添加属性与方法,也可以删除其属性与方法。如:

var person = {}; //创建一个对象 ---引用类型

person.name = 'Mary';

person.age = 22;

person.sayName = function() {console.log(person.name);}

person.sayName(); //'Mary'

delete person.name;  //删除person对象的name属性

person.sayName();  //underfined


上面代码说明来引用类型可以拥有方法与属性,并且可以动态改变


2.引用类型的值是同时保存在栈内存和堆内存中的对象

    js与其它语言不同,其不允许直接访问内存中的地址,也就是说不能直接操作对象的内存空间,那我们操作啥呢实际上,是操作对象的引用,所以引用类型的值是按引用访问的。

准确的说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也就是说该对象在堆内存的地址。

假如有以下几个对象:

var person1 = {name: 'Mary'};

var person2 = {name: 'xioaming'};

var person3 = {name: 'xiaohua'};

这三个对象在内存中保存的情况如下图:

js基本类型与引用类型

3.引用类型的比较是引用的比较

    var person1 = '{}';

var person2 = '{}';

console.log(person1 == person2);  //true

上面讲基本类型的比较的时候提出里当两个比较值的类型相同的时候,相当于用 === ,所以输出是true;

var person1 = {};

var person2 = {};

console.log(person1 ==person2);  //false

这里比较的是两个对象,为啥就不相等了呢:

⚠️别忘了,引用类型是按引用访问的,换句话说,就是比较两个对象的堆内存的地址是否相同,那很明显,person1 和 person2在堆内存中地址是不同的

js基本类型与引用类型

所以这两个是完全不同的对象,所以返回false;


3.简单赋值

从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上:

var a =10;

var b =a;

a ++;

console.log(a); //11

console.log(b); //10

此时,a中保存的值为10,当使用a来初始化b时,b中保存的值也为10,但b中的10与a中的是安全独立的,该值只是a中的值的一个副本,此后,这两个变量可以参加任何操作而相互不受影响。

也就是说,基本类型在赋值操作后,两个变量是相互不受影响的。

4.对象引用

从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到新变量分配的空间中,前面讲引用类型的时候提到过,

保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象,那么赋值操作后,两个变量都保存了同一个对象地址,则两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响:

    var a ={};

var b = a;

a.name = 'Mary';

console.log(a.name); //'Mary'

console.log(b.name);//'Mary'


b.age = 22;

console.log(b.age); //22

console.log(a.age); //22

console,.log(a==b);  //true

js基本类型与引用类型

引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何操作都会相互影响。