细说 JavaScript 函数参数的传递

4,109 阅读3分钟

ECMAScript中所有函数的参数都是按值传递的,就如同把值从一个变量复制到另一个变量一样,并且函数参数也被当作函数的局部变量对待,因此其访问规则与执行环境中的其他变量一样。

我们知道在向参数传递基本类型的值的时候,被传递的值会被复制给一个局部变量(即命名参数,或者说是arguments对象的一个元素),而在想参数传递引用类型的值的时候,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反应在函数的外部。

请看下面的例子:

<script type="text/javascript">
    function addTen(num){
        num+=10;
        return num;
    }
    var count=20;
    var result=addTen(count);
    console.log(result);//30
    console.log(count);//20,没有变化 =>按值传递参数
</script>

在这里函数addTen()有个参数num,而参数实际上是函数的局部变量。在调用函数时count作为参数传递给函数,所以count的数值20复制给了参数num,然后在函数内部num的值加上10,但这一个变化并不影响函数外部的变量count,所以说明函数参数的传递是按值传递。然而我们做个假设,假如num是按引用传递,那么变量count的值也将变成30,但这个假设是否成立呢,因为使用基本数据类型值来说明函数传递的参数是按值传递比较简单,那么我们来使用对象来验证一下我们的假设。请看下面的例子:

<script type="text/javascript">
    function setColor(obj){
        obj.color="red";
    }
    var person=new Object();
    setColor(person);
    console.log(person.color);
</script>

我们很多人错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递。

在上面的例子中我们创建了一个对象,将其保存到变量person中,然后这个变量传递到函数setColor()中之后就被复制给了obj。这说明参数obj与变量person引用同一个对象,换句话说
就是即使这个变量是按值传递的,但obj也会按引用访问同一个变量,所以在函数内部obj添加color属性,函数外部的person也会有所反映。所以为了证明这个错误,让我们看看下面这个例子:

<script type="text/javascript">
    function setColor(obj){
        obj.color="red";
        obj=new Object();
        obj.color="blue";
    }
    var person=new Object();
    setColor(person);
    console.log(person.color);//red =>说明按值传递
    //两个obj指向内存中不同的空间,互不干扰
</script>

在这个例子与前面的例子的区别就是在setColor()函数中添加了两行代码。在这个例子中把变量person传递给函数setColor()之后,person的color属性值已经设置成为red,而之后又创建一个新对象将其赋值给obj,并将color属性值设置为blue。假如我们上面的假设成立,那打印出来的应该是blue,但却是red,所以在所有函数中的参数都是按值传递的。