JS 之 基本类型和引用类型

前奏:在说明这两个类型之前先简单说一下“堆”和“栈”。

 栈:由编译器自动分配和释放,如函数参数、局部变量、临时变量,返回值等等。
 堆:由成员分配和释放,由程序员自己申请、自己释放。否则发生内存泄露。典型为使用new申请的堆内容。

栈空间一般大小固定,能够分配的空间比较小,由系统自动分配,速度较快。

堆空间适合不清楚所要的空间有多大的情况下,需要手工new出来,开销大,容易产生内存碎片。

基本数据类型

JavaScript中基本数据类型有5个 ,Number ,String, Boolean,Null ,Undefined

基本数据类型的值大小一般固定,所以保存在栈空间中,按值来访问。

引用数据类型

引用类型一般比较复杂,值的大小不固定,保存在堆空间中,而将指向堆内存的地址保存在栈空间中(地址大小是固定的)。

当查询某一引用类型的变量时,先去栈空间中找到其值的地址,然后根据地址去堆内存中找到该值,所以是按引用访问。

复制变量值

基本类型的变量在复制时,会在该变量上创建一个和原值一样的新值,然后将该值复制到新变量刚分配的空间中(栈内存)。

引用类型的变量在复制时,复制的是原值的指针,并将该指针写入到新变量刚分配的空间中(栈内存),实际上两个变量指向同一个值。

按值传递 (即形参是实参的副本)

按引用传递 (函数的形参接收实参的隐式引用,而不再是副本,对形参的修改会直接影响到实参)

借上图,按引用传递就是将 (obj1.obj地址)整体传进去。

JS中所有函数的参数传递都是按值传递

 这句话已成为一个不争的事实。

下面说一下函数按值传参的内部原理:

对于基本类型的变量来说,会将该变量的值复制一份传入参数(在ECMAScribe中是函数的一个局部变量,保存在栈内存中),对该参数的操作不会影响到原变量。

对于引用类型的变量来说,会将该变量的值复制一份传入参数,但这个值指向堆内存,是一个地址,对该参数的操作会影响到原变量。

这么说,你可能又会弄混了,这不就是按引用传递么????

我们借用 JavaScript高级程序教程第三版 中一个例子来说明问题。

function setName(obj){
	obj.name="Nicholas";
}
var person=new Object();
setName(person);
console.log(person.name);        //输出 Nicholas

上面这个例子我们会搞混,这难道不是按引用传递么?

我们修改一下:

function setName(obj){
	obj.name="Nicholas";
	obj=new Object();
	obj.name="Greg";
}
var person=new Object();
setName(person);
console.log(person.name);        //输出的还是 Nicholas

下面我们来说明一下:

如果是按引用传递的,那么传递给setName参数obj的应该是 (person.地址)整体(可能说的不太严谨),在函数内部我们重新修改了一下 person.指针 的指向,让它指向一个新地址,并设置name为“Greg”,因此打印person.name应该是“Greg”,然而事实情况并不是。

如果是按值传递,那么传递给setName参数obj的应该是 “地址” 这个值而已,虽然和person的地址值一样,但两者没有任何关联,只是值相同而已。obj参数只是setName函数的一个局部变量,通过操作这个局部变量修改了person,后来obj重新指向了另一个地址,剩下的操作与person无关。

可能上面 (person.地址) 不太准确,但我实在想不到合适的比喻了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值