04-函数参数
6.3 函数参数
现在已经知道如何调用一个函数并在函数外获得它的返回值,那么如何给函数内部传值呢?给函数调用传值的主要途径称为函数参数。参数是指那些在函数调用结束后就不再存在的变量。现在我们来看看这个函数,它有两个数字作为参数,返回这两个数字的平均值。
function avg(a, b) {
return (a + b)/2;
}
在这个函数声明中, a
和 b
称为形参。当函数被调用时,形参会被赋值然后变成实参。
avg(5, 10); // 7.5
在这个例子中,形参 a
和 b
分别被赋值 5
和 10
,成为实参(跟变量赋值很相似,特殊的是它们在函数内)。
初学者很容易犯迷糊的一个概念是:参数只存在于函数内部,即使它们在函数外有相同变量的名字。看下面这个例子:
const a = 5, b = 10;
avg(a, b);
这里的变量 a
和 b
是分开的,这与函数 avg
参数中的 a
和 b
是完全不同的,即使它们的名字一样。在调用函数时,函数的参数只会接收传入的值,而不是变量本身。再看以下代码:
function f(x) {
console.log('inside f: x=${x}');
x = 5;
console.log('inside f: x=${x} (after assignment)');
}
let x = 3;
console.log('before calling f: x=${x}');
f(x);
console.log('after calling f: x=${x}');
运行这个例子,你会看到:
before calling f: x=3
inside f: x=3
inside f: x=5 (after assignment)
after calling f: x=3
这里需要理解的是:在函数中给x赋值并不会影响到函数外的变量x,因为它们是两个不同的实体,只是名字碰巧相同而已。
不论何时给函数中的参数赋值,都不会影响任何函数外的变量。不过,如果在函数内修改了一个对象类型的变量,那么这个改动在函数外也会生效:
function f(o) {
o.message = 'set in f (previous value: '${o.message}')';
}
let o = {
message: "initial value"
};
console.log('before calling f: o.message="${o.message}"');
f(o);
console.log('after calling f: o.message="${o.message}"');
上面的代码会输出如下结果:
before calling f: o.message="initial value"
after calling f: o.message="set in f (previous value: 'initial value')"
这个例子中,可以看到在f函数内部修改了o,这些改动也会影响函数外的o对象。这里强调了基本类型和对象之间的主要区别。基本类型不能被修改(可以改变基本类型所赋值的变量,但是基本类型本身的值不会改变)。从另一方面来说,对象是可以被修改的。
需要清楚的是,函数内的o和函数外的o是完全不同的,但是它们都引用了同一个对象。可以通过下面的代码看出它们的不同之处:
function f(o) {
o.message = "set in f";
o= {
message: "new object!"
};
console.log('inside f: o.message="${o.message}"(after assignment)');
}
let o = {
message: 'initial value'
};
console.log('before calling f: o.message="${o.message}"');
f(o);
console.log('after calling f: o.message="${o.message}"');
如果执行这个例子,会得到如下结果:
before calling f: o.message="initial value"
inside f: o.message="new object!" (after assignment)
after calling f: o.message="set in f"
理解这段代码的关键在于明白参数o(函数内部)和变量o(函数外)是不同的。当f函数被执行时,它们两个都指向了同一个变量,不过当o在 f
函数内被赋值时,它指向了一个全新的、完全独立的对象。而函数外的o依旧指向原始对象。
可以把JavaScript中的基本类型想象成计算机科学中的值类型,因为它们在赋值的过程中都对原始值进行了复制。对象则称为引用类型,因为当它们在赋值时,被赋值的变量和原来的变量都引用了同一个对象(也就是说,它们拥有同一个对象的引用)。