1. 按值传递
ECMAScript中函数的参数都是按值传递,指的是把函数外部的值复制给函数内部的参数,相当于把值从一个变量复制到另一个变量。
2. 基本类型的传值
我们知道,基本类型值在内存中占据固定大小的空间,保存在栈内存中;基本类型的复制是拷贝一份副本给另一个变量,两个变量参与任何操作不会相互影响。
所以,在向函数参数传递基本类型的值时,被传递的值会复制给函数的一个局部变量。
看下面一个简单的栗子:
|
|
相信你已经猜到上面的代码会打印出什么?。。?
代码中,函数add()有一个参数num,作为函数内部的一个局部变量,当函数被调用时,将count的值20复制给add()函数内部的局部变量num,并且不会影响到函数外部声明的count变量。num和count相互独立,只是具有相同的value。
3. 引用类型的传值
在向函数传递引用类型的值时,同样是把函数外部的引用类型变量复制给函数的一个局部变量。
但是引用类型的复制与基本类型的复制稍稍有点不同。
当一个引用类型的值复制给另一个值的时候,是将引用类型的存储在栈内存的指针复制一份,分配给一个新的变量,这两个指针指向的是同一个存储在堆内存的对象。所以复制后的变量和原来的变量引用同一个存储在堆内存中的对象,它们的改变会影响到另一个。
同样来一段代码:
|
|
用图片表示如下:
所以当通过复制后的变量n改变堆内存中的值,同样会影响到原来的变量m。
|
|
理解了上面的内容后就很容易理解函数参数传递引用类型的值了。。。
下面看一个红宝书上面的例子:
|
|
代码中person变量为引用类型的对象,当传入到setName函数时,复制给函数的局部变量obj,所以person和obj指向同一块堆内存。所以在函数内部为obj增加name属性时,person也能通过相同的指针读取到name值。不同的是函数内部的局部变量obj会在函数执行完毕后被销毁。
所以函数参数传递引用类型指的是传递变量地址的值(栈内存中,即指针的值)。
后面红宝书还改了一下上面的例子,来证明函数参数是按值传递(而非按引用传递)的
|
|
上面的 obj = new Object(); 相当于给函数的局部变量obj分配了另一个指针,使其指向另一个存储在堆内存的对象,与函数外部的person变量的联系完全断掉。
所以函数参数按引用传递的定义是什么???直接传递引用类型存储在堆内存的值???其实引用类型的访问规定是按引用(即指针)访问,所以我的理解函数参数传递引用类型传递的就是指向同一个堆内存的对象的地址值(指针值),相当于按值传递。
另外,还有的观点是引用类型是按共享传递的,这里不展开论述…
4. ES6中的函数参数传递
ES6允许为函数参数设置默认值
|
|
当设定了函数的默认值后,在函数进行声明初始化时,参数会形成一个单独的作用域。初始化结束后,这个作用域会消失。看下面的例子:
|
|
代码中,参数y的默认值等于变量x。而函数调用时参数会形成一个作用域,该作用域内,函数的参数x接收的值为2,所以y的值为2。再看一个例子:
|
|
这个例子中,foo调用时,(y = x)形成一个单独的作用域,在该作用域内,x没定义,所以此时x是指向全局作用域中的x。
最后来看一个复杂一点的例子:
|
|
上面的代码,foo函数的参数形成一个单独的作用域。该作用域中,声明了变量x、y,y是一个匿名函数,匿名函数内部的x指向foo函数的第一个参数x,函数foo内部又声明了一个x变量,由于该x与foo()参数的x不在同一个作用域,所以不是同一个变量,所以执行y()后,foo()内部的x和全局变量x的值都不变。
如果将var x = 3的var去掉,则foo内部的x指向其第一个参数的x,最后会输出2,而全局变量依旧不会变。
End……