JS参数传递(值传递和引用传递)

前端红宝书第一遍看过去之后,相当多的东西都忘记了,第二遍看的时候,也开始注意到一些细节的东西以及理解不到位的地方。

书P66 一个加粗框中写到:ECMAScript中所有参数传递都是值,不可能通过引用传递参数

当时看过没有怎么仔细想过,一知半解吧,今天理解的更加深一些。当然也是昨天做了个题目就因为这个掉坑里一时没爬出来!

访问变量有按值和按引用两种方式,而参数只能按值传递。

一、基本数据类型: Number, String等都是按值传递这个好理解,当时我也就理解这个吧。

var a = 10
function add(num){
	num+=10
}
add(a)
console.log(a)

如上面的代码,执行add(a)的时候,会复制一份值给函数的arguments这伪数组,当然同时也是num这个命名参数。arguments[0] = num,函数内部对num进行了加操作,num = 20了。但是外部最后输出a时,仍然是10,说明a与函数内部的num互不干扰。其实此时可以把命名参数看成是局部参数,函数运行结束,它也随之销毁。而它是按值传递的,复制了内存中的一份值给num。所以内部对num的操作不影响全局变量a的值


二、基本类型的值好理解,但是JS中对象类型的就不怎么好理解了,反正令我觉得有点绕;

先看例子:

var student = new Object()
function addNum (obj) {
	obj.num = '23'
}

addNum(student)

console.log(student.num)

如上,首先定义了一个student对象,然后通过函数给该对象添加了num学号的属性值:23。之后打印输出的时候,很奇怪,居然给student对象添加上了属性,并且影响到了外部对象,这传值明显就是引用传递啊,函数内部obj和student都指向堆中同一个对象。就是引用传递嘛。但是又和红宝书上写的矛盾:不可能通过引用传递参数??这就莫名奇妙了。

查阅了很多大神写的说明,但是感觉都不能够说明,真是非常难理解。我觉得是不是这样理解:以上述函数为例,我把student对象实例作为参数传递给obj时,是将student所指对象的地址复制了一份给obj,这样obj空间所存的地址和student就都指向了共同的存储空间。而如果是引用传递的话,obj是没有空间的,它将会和student公用一个空间,这个空间就保存着一个指向student实例对象的地址。

下图为说明:传值

下图为引用传递的情况:

为了验证,我们来看下面的代码:

var student= new Object()

function addName(obj){
obj.name = ‘roddan’
obj = new Object()
obj.name = ‘liujiang’
}

addName(student)

console.log(student)

注意: 对于对象等引用类型的数据,“=”操作会覆盖掉原来的地址值。

分析: 如上代码,我们先将student=》 obj对象,然后为它增加了name属性为:“roddan”。之后我们将obj指向了一个新的对象,然后为它同样增加了"name"属性值:“liujiang”。但是我们最后输出的仍然是“roddan”,这里就不贴图了,代码简单,各位自己验证就好。那么问题来了,如果是引用传递的话,如上面图所示,在将obj重新指向新的对象时,会等同于在执行student空间所保存的地址"0x41",如果将它覆盖掉的话,外部最后打印student时,应该打印的对象是重新定向的name:“liujiang”的这个对象。但事实是打印出来的是name: “roddan"的这个对象。也就是说,obj复制了一份地址保存在自己的空间,当仅对它本身操作时,它指向的是student共同指向的对象。但是当我操作 obj = new Object()时,它自己空间保存的地址将会被新的对象的存储地址所覆盖,因为是传值不是引用,所以它不会影响到student空间所保存的地址,故最后虽然对obj的name属性重新赋值,但也丝毫不影响之前赋值结果,最终输出的仍为"roddan”。

这就让我想起了昨晚一位网友做题时碰到的问题:

题目如下: 附上网址: 点击打开链接

/**
  • @param {number[]} nums
  • @param {number} k
  • @return {void} Do not return anything, modify nums in-place instead.
    */
    var rotate = function(nums, k) {

};

有位同学的代码是这样的:

var rotate = function(nums, k) {
var len = nums.length;
var newArr = nums.splice(0, len-k)
var temp = nums.concat(newArr)
nums = temp
};

var a = [1,2,3,4,5,6,7]

rotate(a, 3)
console.log(a)

而最终网站提示:



当时他找不到原因,应该是这样啊,a数组最后输出怎么就只有[5,6,7]了呢,其实这里就是函数传参只传值而不是引用理解的不透彻。nums中复制了一份指向a数组的地址,你只能对其本身进行操作,也就等同于在操作数组a。但是当你来了句:

nums = “某某” 的时候,这问题就来了。“=”会覆盖掉nums中保存的指向a数组的地址。并将其新地址指向temp.concat(newArr)这个新数组,那么此刻,nums已经完全是个局部变量了,而且地址的改变使你无论对它进行什么操作都不会影响到a数组上面来。故最后输出的就只是之前对a数组截取剩下的部分[5,6,7]。

正确的做法就是不要改变nums中保存的指向a数组的地址,这样对nums的操作就会影响到a数组上面来。达到题目的要求。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值