ECMAScript函数参数只会按值传递,不会按引用传递

ECMAScript的一些语法规范都是参照C语言来制定的,C语言中定义函数参数时,可以指定基本类型参数(int,float,double等等)也可以指定引用类型参数(指针)。其中引用类型参数是指给函数传入变量的地址,然后函数内部处理引用类型参数(实际上操作的是指向变量的地址的副本,副本指向同一内存块)时,外部的引用类型变量也会随着改变。

需声明一点的是C语言只支持按值传递机制,不支持按引用传递机制(按引用传递机制是c++里面才有的特性)。对于基本类型参数,形参值为实参值的一个副本;对于引用类型参数,形参值为实参地址值的一个副本。

接下来我们来看下ECMAScript的参数传递机制。如下,我定义一个函数sum,然后分别定义一个基本类型参数和引用类型参数:

给sum指定基本类型参数示例:

var num = 0;
var result = 0;
function sum(iNum)
{
    iNum += 10;
    return iNum;
}
result = sum(num);
console.log(result);    //值为10
console.log(num);    //值为0,没有变化
给sum指定引用类型参数示例:

var obj = new Object();
obj.name = "zhangsan";
obj.age = 26;
function chgName(oPara)
{
    oPara.name = "lisi";
}
chgName(obj);
console.log(obj.name);    //obj.name的值变为lisi
从以上两个示例看出,当给函数指定引用类型参数时,在函数内部改变引用类型参数的属性时,全局变量的值的属性也发生变化。这时我们就会怀疑,既然全局变量的属性已经改变了,那么不能说明ECMAScript函数参数可以按引用传递吗?答案是不能,我们再来看以下示例。

var obj = new Object();
obj.name = "zhangsan";
obj.age = 26;
function chgName(oPara)
{
    oPara.name = "lisi";   //仍然指向旧对象,对oPara属性name的值的修改会反映在旧对象上
    oPara = new Object();  //此时创建一个新对象,oPara的值为新对象的地址值,指向新对象
    oPara.name = "zhaowu"; //这里是改变新对象的属性值,但不会影响旧对象,因为他们互相独立
}
chgName(obj);
console.log(obj.name);    //为lisi

可以看出,obj.name仍然为lisi。在函数内部重新定义oPara,并设置name的值为zhaowu时,外部变量并没有改变,仍然是lisi。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,在函数内部重新定义对象oPara时,oPara引用的就是一个局部变量了。这个局部变量在函数执行完毕后就会被销毁(为《JavaScript高级程序设计》上的说法)。

以我个人理解及在网上查资料得知,oPara的值为obj的一个副本,同时指向堆内存中的引用变量obj。当给oPara重新赋值时,此时会在堆中创建一个新对象,此时oPara的值变为新对象的地址,同时指向新对象。此时旧对象与新对象是两个独立的的对象,对新对象的操作并不会影响旧对象。当函数执行结束后,在函数内部创建的新对象会一并销毁。而对旧对象的属性的改变则会反映在旧对象上。

引用类型变量存储在堆内存中,js不可以直接操纵,但可以通过栈中对引用类型的引用(即地址)来改变变量的值。

总之,记住一句话,ECMAScript中只有按值传递。

猜你喜欢

转载自blog.csdn.net/y2010081134/article/details/70193986