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"。
这就让我想起了昨晚⼀位⽹友做题时碰到的问题:js arguments
题⽬如下: 附上⽹址:
/**
* @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 = at(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数组的地址。并将其新地址指向
正确的做法就是不要改变nums中保存的指向a数组的地址,这样对nums的操作就会影响到a数组上⾯来。达到题⽬的要求。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。