JS的方法参数传递(按值传递)

330 阅读4分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

一句话总结

JS的方法参数是按值传递

前提

ES变量分为两种数据类型的值:基本类型和引用类型

基本类型存储

基本类型的值在申请内存时是固定大小,所以保存在栈内存,故在复制基本类型变量时也是在栈内存中新开辟一份内存空间进行存储

引用类型存储

而引用类型变量的值大小不固定,且可任意改动,引用类型变量的本质是指向某一块内存区域的指针变量,故引用类型变量存储在内存自由分配的堆内存中,在对引用变量作直接复制(重新赋值)时也只是将新的变量指向相同的一片内存区域(即两个指针指向同一片堆内存空间)

引用类型探析

引用类型的值是存放在内存中的对象,但由于JS语言不允许直接访问内存中的位置(即不能直接操作对象的内存空间),故操作对象时实际是在操作对象的引用,而不是直接操作实际的对象本身(即引用类型的值是按引用访问的,这个引用可以理解为对象的句柄)

特别地

很多语言对于字符串是以对象形式进行表示,故为引用类型变量,但ES不是

详解

ES中所有函数(方法)的参数都是按值传递的,即调用一个方法时,是将调用该方法时传入该方法的参数的复制给函数内部的参数(将实参的值复制给形参)

具体分类

JS在访问变量时有按值和按引用两种方式,但参数只会按值传递

向参数传递基本类型的值

被传递的值会被复制给一个局部变量(这个局部变量就是形参,在ES中就是arguments对象的一个元素)

实例
function addTen(num) {
  num += 10;
  return num;
}
var count = 20;
var result = addTen(count);
// 看有没有影响到原变量
alert(count);
alert(result)

执行结果

20
30

向参数传递引用类型的值

JS会把被传递的值的地址复制给一个局部变量,因为复制的是地址,所以在函数执行时,函数形参在函数内部改变时会影响到函数外部的该引用变量的值,因为两个地址指向同一片内存区域,但在函数执行结束,函数内部的局部变量被销毁,影响即会消失

实例
function setName(obj) {
  obj.name = 'tom';
}
var person = new Object();
setName(person);
// 当把person传递给setName时,obj和person都指向相同的内存,所以对obj所指向的内存区域修改会影响到person
alert(person.name);

执行结果

tom
分析

因为person指向的对象在堆内存中只存在一个,并且是全局对象

求证参数是按值传递而不是按引用传递

function setName(obj) {
  obj.name = 'tom';
  obj = new Object();
  obj.name = 'jerry';
}
var person = new Object();
setName(person);
// 当把person传递给setName时,obj和person都指向相同的内存,所以对obj所指向的内存区域修改会影响到person
alert(person.name);

执行结果

tom
结论

函数内部重新生成的对象obj,并对其新赋值jerry并没有改变函数外部person对应的属性值

如果向引用类型参数赋值是按引用赋值,那么person的name应该变为jerry,因为假设形参obj拿到的是person的引用,而不是person引用的值,那么当函数内部生成新对象,并对obj进行重新指向时,形参obj的指向改变,外部的person的指向也应该改变,但是结果证明alert(person.name)显示的依旧是tom,所以即使函数参数是引用类型,也是按值传递

而实际上在函数内部重写obj时,这个变量引用的是一个局部对象变量,该局部对象会在函数执行完毕之时销毁