一篇搞懂值传递和引用传递

在各种教程中,大家可以经常看到这句话:

ECMAScript中所有参数传递的都是值,不可能通过引用传递参数

但是在实际应用的时候,似乎没有这么简单,今天我们来聊一下在js调用函数传递变量参数时,到底是值传递还是引用传递呢?在此之前,先和大家插入一个小知识:

关于引用变量赋值问题

  • 两个引用变量指向同一个对象,通过一个变量修改对象内部数据,另一个变量看到是修改之后的数据
var obj1={name:'Tom'}
var obj2=obj1
obj2.age=12
console.log(obj1.age) //12
function fn(obj){
    obj.name='A'
}
fn(obj1)
console.log(obj2.name) //A

在真正明白这个例子前,我们先来确定一下自己是否真正理解变量的含义:var a=xxxx,a内存中到底保存的是什么?
我们分三种情况来讨论:
1.xxxx是基本数据,保存的就是这个数据
var a=3;
2.xxxx是对象,保存的是对象的地址值
var a=function(){ }
3.xxxx是一个变量,保存的xxxx的内存内容(可能是基本数据,也可能是地址值)

重新回到我们的这个例子,obj2和obj1指向了同一个对象,并且通过obj2对该对象的age属性进行了修改,这个时候改变的是obj2指向的对象的本身,又因为obj1和obj2指向的是同一个对象,所以在打印obj1.age的时候,输出的结果是更改过后的结果,也就是12。
在通过fn函数将obj1传递进去之后,相当于是obj=obj1,此时已经将obj和obj1指向了同一个对象,这个时候,obj、obj1、obj2三个变量指向了同一个对象。那么在函数中对对象的name属性更改了之后,再打印obj2的name属性就理所当然的为更改之后的值,即A。

  • 两个引用变量指向同一个变量,让其中一个引用变量指向另一个对象,另一个引用变量依然指向前一个对象
var a={age:12}
var b=a
a={name:'BOB',age:13}
b.age=14
console.log(b.age,a.name,a.age)//14  Bob  13

function fn2(obj){
    obj={age:15}
}
fn2(a)
console.log(a.age) //13

在这个例子中,var b=a 让b和a指向了同一个对象,但是,a={name:‘BOB’,age:13}使a的指向对象发生了改变,但是b还指向之前的对象,所以在b的age属性发生改变的时候,与a指向对象已经没有关系了,所以输出b的age属性应该是更改之后的age属性值,但是a的name属性和a的age属性应该是新指向对象的值。
在通过fn2函数将a传进去之后,相当于obj=a,此时obj和a指向了同一个对象,但是在函数体内,obj={age:15} 使obj的指向对象发生了改变,此时obj已经成了一个局部的变量,和a指向的对象已经互不相干,在执行完函数之后obj对象将自动销毁,并且obj所做的任何操作与全局变量的a没有任何关系,所有打印出的a的age属性仍然为13。

好了,在有了上述的基础之后,我们开始探讨我们今天的主要问题。

值传递还是引用传递?

我们分为两个部分来分析:

  • 基础数据类型
var a = 10
function add(num){
	num+=10
}
add(a)
console.log(a) //10

基本数据类型比较简单,在add函数中传入a的时候,只是将a的值复制了一份给了num,num可以看做一个局部的变量,他所做的任何操作都影响不到全局变量a,函数运行结束的时候num也会随之销毁,所以在打印a的时候,a的值仍然为初始值10。在这里值传递的思想完美诠释,没有任何问题。

  • 对象类型
var student = new Object()
function addNum (obj) {
	obj.num = '23'
}
addNum(student)
console.log(student.num) //23

在对象类型的时候,我们发现和基本数据类型不同,函数内部对obj的num属性的改变竟然也改变了student对象的num类型,这个时候,这个结果和我们开篇的那句话ECMAScript中所有参数传递的都是值,不可能通过引用传递参数似乎矛盾了???这是怎么回事呢?
把student对象实例作为参数传递给obj时,是将student所指对象的地址复制了一份给obj,这样obj空间所存的地址和student就都指向了共同的存储空间。也就是说,obj和student指向了同一个对象。等等!!!这不就回到了我们上一个问题中的引用变量赋值问题吗?有没有豁然开朗的感觉?!因obj和student指向了同一个对象,那么,在obj对对象更新的时候,studen同样也更新,打印出的student的num值理所应当的就为更改之后的值了,即23。

  • 练习一下
var student= new Object()
function addName(obj){
obj.name = ‘haha’
obj = new Object()
obj.name = ‘lala’
}
addName(student)
console.log(student.name) //haha

在这个例子中,将student传入addName函数中,此时student和obj指向了同一个对象,并且通过 obj.name = ‘haha’对对象添加了name属性并且赋值为haha。但是在下一步,obj = new Object(),也就意味着obj重新指向了一个新的对象,此时obj变为了一个局部的变量,并且与全局变量student毫无关系,在函数执行完毕的时候,obj也会随之销毁。所以在打印student的name属性的时候会打印出来haha。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值