详解JavaScript基本数据类型和引用类型的区别、值传递和引用传递

一、JavaScript基本数据类型和引用类型的有什么区别?

在JavaScript中,简单的基本数据类型有:Number数值类型,Boolean布尔类型,undefined未定义类型,null是基本数据类型还是引用类型?null也是简单的值类型,常见的JavaScript引用类型有Object对象类型,Array数组类型,Date日期类型,另外JavaScript中String类型究竟是基本类型还是引用类型?一方面String类型具有可变长度,而基本类型一般长度固定,所以String类型和引用类型也比较相似,在C++中String是引用类型,在这里String做基本类型处理(实际上ECMAScript并没有分基本类型和引用类型,平时对其分类一般都是基于它们的内存结构的不同)。

基本数据类型和引用类型的根本区别在于其数据在内存中的存储位置不同,基本数据类型存储在栈内存中,而引用类型存储在堆内存中,栈内存由系统自动分配自动释放,按顺序存储,而堆内存中的数据则是动态向系统申请空间,存储的顺序并不是连续的,如下一段代码:

var height = 90; // 数值类型变量
var isReleased = true; // 布尔类型变量
var title = "Next" // 字符串类型变量

var user = {}; // 对象,引用数据类型
user.id = 123;
user.isRoot = false;
user.name = "Visual";
user.email = "git@git.com"

height、isReleased和title都是基本数据类型,所以存放在栈空间中,代码块执行完则自动释放,user是一个引用类型的对象,其数据存放在堆内存中,代码块执行完不一定自动释放,由JS引擎决定什么时候回收,在C/C++中需要手动释放,它们的内存结构布局如下:

JavaScript基本数据类型和引用数据类型的内存结构

不管数据存储在栈内存中还是堆内存中,访问都是使用地址或指针访问实际的数据的,每个变量名对应着一个地址,每个地址对应实际的数据,对象的存储方式又有不同的地方,首先对象的变量名user对应地址0x004存储的是一个地址0xFFABCD,这个地址0xFFABCD就是对象实际的数据在堆内存中的地址,所以当你将user赋值给另一个变量的时候,实质上是将user保存的地址0Xffabcd复制给目标变量了,但是user对应堆内存空间中的数据并没有改变或复制。

二、什么是值传递和引用传递,它们有什么区别?

值传递一般说的是数据的值传递,引用传递一般说的是传递数据的指针,值传递和引用传递是一个模糊的称呼,因为所谓的引用传递也是值传递,基本来说只有一种那就是值传递,而我们需要区分的究竟值传递中,引用类型和基本类型的变量对应的数据有没有被复制,如果目标数据内容被复制了,那么后面的修改就不会影响原来的数据内容,如果没有被复制,那么对数据并没有改变,使用其它变量对数据进行修改则是影响原理的数据内容。

值传递和引用传递的产生一般有两种,一种是基本的赋值操作,另一种是函数的参数传递,下面先看第一种:

// 1、赋值传递
var number1 = 78;
var number2 = number1; // 将number1的值复制一份赋值给number2
number2 = 80;
console.log(number1); // 输出78

var song = {
    title: "Nake",
    content: "lyrics"
}
var temp = song; // 将song的地址复制一份复制给temp
temp.title = "Time";
console.log(song.title); // 输出Time

上面发生的值传递和应用传递如下图:

JavaScript值传递和引用传递图解

对于基本数据类型,它们都是存储在栈空间中的,在赋值时都对源数据进行拷贝,然后赋值给目标变量,这种就称之为值传递。对于引用类型,temp和song都是对象类型,这两个变量实际保存的是数据在堆内存中的地址0xffabcd,将song赋值给tmep的时候也是讲song保存的内存地址复制一份给temp,所以后面temp对0xffabcd的数据进行修改,实际上还是原来的那个数据内容,这种就称为引用传递。

第二种是函数的参数传递,例如:

// 2、函数参数传递
var user = {
    id: 90,
    name: "Coder"
}
function login(u, code){ // u使用应用传递,即将user的地址复制给u,code直接复制数据
    console.log(u.id, u.name, code);
    u.id = 7; // 修改user的id为7
    code = 500; // 修改code的值为500
}

var code = 200;
login(user, code);
console.log(user.id, code); // 输出7 200

可以看到效果和普通复制的传递情况一样,所以对于值传递还是引用传递,主要是看其数据实际保存的位置是在栈中还是在堆中,基本数据类型都在栈中,而引用类型都在堆中,平时我们可以根据这些来判断。

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?