写在前面:ECMAScript访问变量有
按值
和按引用
2中方式,那函数的传参呢?是按值传递还是按引用传递?之前有专门介绍:javascript中的引用类型 和 普通类型
在向参数传递 基本类型
的值时,被传递的值会被赋给一个局部变量(即命名参数/arguments对象中的一个元素):
//demo1:
function add(n) {
return n += 100;
}
var _count = 100;
var result = add(_count);
console.log(result); //200
console.log(_count); //100
//_count没有变化,因为是值传递,内部的变化不会反映到函数外部。
一切都向我们预想中的方向发展了,
但是~~在向参数传递 引用类型
的值时:
//demo2:
function setName(p) {
p.name = 'hello';
}
var person = new Object();
setName(person);
alert(person.name); //hello
参数传递不是按值传递的吗?为什么内部 obj
的变化,会反映到外部的 person
对象上?
~
~
~
在向参数传递 ‘‘引用类型’’ 的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。
以上代码创建的一个对象并保留在一个变量person
中。然后,person
在执行setName()
函数时被复制给了p
,在这个函数内部,p
和person
引用的是同一个对象。
换句话说,即使变量person
是按值传递的,p
也会按引用
来访问同一个对象。
所以,当执行p.name = 'hello'
,外部的person.name => hello
,因为person所指向的对象在堆内存中只有一个,而且是全局对象。
这里有一个很大的误区:在局部作用域中修改的对象会在全局作用域反映出来,就说明参数是按照引用传递的,这个是错误的。。。举个栗子:
把demo2
中的代码修改为demo3
:
//demo3:
function setName(p) {
p.name = 'hello';
p = new Object();
p.name = 'world';
}
var person = new Object();
setName(person);
alert(person.name); //输出仍然是 hello
~~~
上面的例子很好的解释了函数参数的按值传递
。
即使在函数内部修改了p
的值,但是原始的引用依然保持不变的。
当在函数内部重写p
的时候,这个变量的引用就是一个局部对象了。而,这个局部对象,会在函数执行完毕后自动销毁。
再来看个例子demo4
:
//demo4:
function setName(p) {
p = {
name : 'world'
}
p.name = 'hello';
}
var person = new Object();
setName(person);
alert(person.name); //undefined
demo4
输出undefined
,对比demo3
应该比较容易理解,p
在函数内部被重写了,这个时候变量引用的就是一个局部对象,这个局部对象会在函数执行完毕后自动销毁。
小结:ECMAScript中所有函数的参数都是按值传递的~~