Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 10 additions & 28 deletions grammar/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ f(0) // 0

### 传递方式

JavaScript的函数参数传递方式是传值传递(passes by value),这意味着,在函数体内修改参数值,不会影响到函数外部
JavaScript的参数传递方式是全部都是“传值传递”(passes by value),只不过当一个变量指向对象(包括数组)时,该“变量”其中的“值”即为该对象的引用,当变量中的值为某对象引用时,改变该“变量”的“值”时,并不会影响其所指向对象本身以及其中的值,而是仅仅指向另一个引用或者被替换成其他值。然而,当你利用被传入的变量改变其所指向对象中的属性或者方法时,那么即时在函数内部,该变量也将会改变函数外部对象中属性或方法的值,因为该变量的值为函数外对象的引用,我们通过该引用访问了其中的属性或方法,并且修改了它

{% highlight javascript %}

Expand All @@ -547,45 +547,27 @@ p // 2
// 修改复合类型的参数值
var o = [1,2,3];

function f(o){
o = [2,3,4];
function f(o){ // 这里o变量有其自己的内存地址,只不过里面的值存储了和函数外部o相同的引用到数组[1,2,3]
o = [2,3,4]; // 这时函数内部的o变量被存储了新的引用,即为数组[2,3,4]的地址, 注意:这里我们丝毫没有改变原数组[1,2,3],只是覆盖了一个新变量而已,但函数外部的o依然指向[1,2,3],所以值不会变
console.log(o); // [2,3,4]
}

f(o);
o // [1, 2, 3]

{% endhighlight %}

上面代码分成两段,分别修改原始类型的参数值和复合类型的参数值。两种情况下,函数内部修改参数值,都不会影响到函数外部。

需要十分注意的是,虽然参数本身是传值传递,但是对于复合类型的变量来说,属性值是传址传递(pass by reference),也就是说,属性值是通过地址读取的。所以在函数体内修改复合类型变量的属性值,会影响到函数外部。

{% highlight javascript %}

// 修改对象的属性值
var o = { p:1 };
// 修改复合类型其中的属性

function f(obj){
obj.p = 2;
}

f(o);
o.p // 2
var q = [1,2,3];

// 修改数组的属性值
var a = [1,2,3];

function f(a){
a[0]=4;
function changQ(cq) {
cq[0] = 5; // 我们通过cq变量中的引用访问到[1,2,3]的地址,并且改变其中的值,注意这次,我们通过传进来的“值”(数组q的地址)访问并且改变了q数组,由于函数外q变量所指向的也是该数组,所以也改变了函数外部q的值,因此看似好像达到了按址传递的效果,其实cq变量有其自己的内存地址,只是其“值”存储了复合类型的引用
}

f(a);
a // [4,2,3]
changQ(q);
q // [5, 2, 3]

{% endhighlight %}

上面代码在函数体内,分别修改对象和数组的属性值,结果都影响到了函数外部,这证明复合类型变量的属性值是传址传递。

某些情况下,如果需要对某个变量达到传址传递的效果,可以将它写成全局对象的属性。

{% highlight javascript %}
Expand Down