JavaScript函数参数,传值还是传址?

标签: , , , , ,

首先,十万以及万分肯定的说一句, JavaScript 函数传递参数时,是值传递。虽然您可能不信,因为 ECMAScript 变量可能包含两种不同数据类型的值:基本数据类型,和引用数据类型。难道引用数据类型传递的时候难道也是值传递吗?答,没错。

引用类型的值是什么东西?

当一个变量向另一个变量复制引用类型的值时,会将存储在栈中的值(栈中存放的值是对应堆中的引用地址)复制一份到为新变量分配的空间中。

不同的是,这个值的副本其实是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上引用同一个对象。

var user = new Object();
var admin = user;
admin.name = "xiaoxiaozi";
alert(user.name); //返回 xiaoxiaozi

该过程其实是这样的(引用型变量的复制):

copy

所以说,引用类型的值实际上是对其引用对象的一个指针。


函数参数的传递

基本类型我们不做讨论,那玩意除了值还真没别的。咱们继续来说引用类型。请看下面示例:

function setName(obj){
    obj.name = "xiaoxiaozi";
}
var person = new Object();
setName(person);
alert(person.name); // 返回 xiaoxiaozi

在向参数传递引用类型值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

ECMAScript 中,所有函数的参数都是按值来传递的。基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),引用类型值的传递和引用类型变量的复制一致(栈内存放的是指针,指向堆中同一对象)

因此在调用函数setName()时,person 被复制给了 obj ,因此在函数内部 obj 与 person 引用的是同一个对象,或者说是对同一个对象的引用。所以在给 obj 引用对象加上 name 属性时,person 引用的对象也有了 name 属性,因为虽然 obj 与 person 不同,但是二者引用的对象是同一个。

但是,千万不要认为,在局部作用域中修改的对象会在全局作用域中反映出来就说参数是按引用传递的。为了证明是值传递,让我们再来看如下例子:

function setName(obj){
    obj.name = "xiaoxiaozi";
    obj = new Object();
    obj.name = "admin";
}
var person = new Object();
setName(person);
alert(person.name); // 结果依旧是 xiaoxiaozi

在调用 setName() 函数初时,obj 与 person 引用的是同一对象,所以首次的 name 属性赋值会对 person 有所影响。但是当 obj 被重新定义时,其引用的对象已经与 person 不同,所以后面设置的 name 属性,不会对 person 引用的对象有任何影响。

感觉上面的这个例子非常好,大家可以仔细体会一下,我也是看到了这个例子才决定从文中摘抄(貌似没有摘,就是抄)的。

原文链接:JavaScript 传递参数是值传递?还是值传递啊?

赞赏

微信赞赏支付宝赞赏

随机文章:

  1. MySQL字符集与排序方式
  2. 批处理技术内幕:序
  3. 你可以分配多大的内存?
  4. eXeScope注册码算法
  5. 用JavaScript实现PHP的urldecode函数

4 条评论 发表在“JavaScript函数参数,传值还是传址?”上

  1. linkanyway说道:

    最近你躲哪去了?

  2. kamal说道:

    确实只有抄,只是把“Nicholas”改成了“xiaoxiaozi”。
    而且原文没有解释清楚的最后一个例子这里也没有解释。
    所以说就是直接抄嘛,《professional javascript for web developers》中译《javascript高级程序设计 第二版》62~63页

  3. 晨曦说道:

    不错,看了书还有点不太明白,看了你的bolg后十分明了,主要就是参数复制的是指针,记住这个就好理解了。

  4. 阿南北去说道:

    为什么你明明都知道是传了地址进去,却好坚持说传的是值? 在最后一个例子中,一开始obj和preson都是指向同一块地址的地址变量名,但当obj重新赋值于一个new Object 的时候,obj已经是另一块地址的地址变量了,于是对obj的操作也就是对那个新开劈的地址进行操作,当然就影响不到旧地址,因此在使用preson这个旧地址变量名的时候,只能读出旧地址的值。

留下回复