1. 参数:我们在调用函数时给函数提供的一些额外信息
  2. 使用 **()** 函数调用符来调用函数,在调用函数的时候,可根据需要传递参数:
    1. **<函数名>()**
    2. **<函数名>(参数1, 参数2, ...)**
  3. 获取函数 f 定义的参数个数:f.length
  4. JS 允许省略参数
    1. 在调用函数时,传参数量可以比定义的参数数量时少
    2. 未传递的参数默认为 undefined
    3. 若想省略前面的参数,可以显式地传 undefined
  5. JS 允许额外参数
    1. 在调用函数时,传参数量也可以比定义的参数数量多
    2. 可以通过 arguments 对象来获取额外参数
  6. “原始类型参数”和“引用类型参数”
    1. 原始类型参数:传递方式是传值传递(passes by value)
    2. 引用类型参数:传递方式是传址传递(pass by reference)
  7. 定义函数时,忌出现同名形参

概述

在 JS(及其他编程语言)中,函数是一个执行特定任务的代码块。为了让函数更加通用和可重用,我们经常需要提供一些外部信息给它。这些信息被称为“参数”(或者“形式参数”)。当你调用一个函数并传递一些值给它时,这些值被称为“实际参数”。

这是一个简单的例子:

  1. function sayHello(name) {
  2. console.log("Hello, " + name + "!");
  3. }
  4. sayHello("Alice"); // 输出:Hello, Alice!

在上面的代码中,函数 sayHello 有一个参数 name。当我们调用函数并传递字符串 “Alice” 时,name 参数的值就是 “Alice”。

函数可以有多个参数,也可以没有参数。多个参数之间用逗号分隔。

例如:

  1. // 求两数之和的函数
  2. function add(a, b) {
  3. return a + b;
  4. }
  5. console.log(add(3, 4)); // 输出:7

在这个例子中,add 函数有两个参数:ab。我们调用函数并传递了两个值 3 和 4 给它,然后函数返回了它们的和。

  1. // 求正方形面积的函数
  2. function square(x) {
  3. return x * x;
  4. }
  5. square(2) // 4
  6. square(3) // 9

上式的x就是square函数的参数。

JS 允许省略参数

函数参数不是必需的,JS 允许省略参数。如果一个参数没有传值,那么这个参数的值将为 undefined。

  1. function f(a, b) {
  2. return a;
  3. }
  4. f(1, 2) // 1
  5. f(1) // 1
  6. f() // undefined
  7. f.length // 2

上面代码的函数f定义了两个参数,但是运行时无论提供多少个参数(或者不提供参数),JavaScript 都不会报错。省略的参数的值就变为undefined。需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。

  1. function showInfo(name, age) {
  2. console.log("Name:", name);
  3. console.log("Age:", age);
  4. }
  5. showInfo("Alice");
  6. // 输出:
  7. // Name: Alice
  8. // Age: undefined

在这个示例中,在调用函数 showInfo 时,我们仅传入了一个参数 "Alice",此时 age 并没有传值,它将默认为 undefined

但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入**undefined**

  1. function f(a, b) {
  2. return a;
  3. }
  4. f( , 1) // SyntaxError: Unexpected token ,(…)
  5. f(undefined, 1) // undefined

上面代码中,如果省略第一个参数,就会报错。

JS 允许额外参数

在调用函数时,JS 对于参数的约束是比较随意的:

  1. JS 允许省略参数,传递的参数比定义的参数数量少
  2. JS 还允许额外的参数,传递的参数比定义的参数数量多

如果你为函数提供的参数多于函数声明的参数,额外的参数不会被赋值给任何命名参数。但是,这些额外的参数仍可以通过函数内的 arguments 对象访问。

“原始类型参数”和“引用类型参数”

函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。

  1. var p = 2;
  2. function f(p) {
  3. p = 3;
  4. }
  5. f(p);
  6. p // 2

上面代码中,变量p是一个原始类型的值,传入函数f的方式是传值传递。因此,在函数内部,p的值是原始值的拷贝,无论怎么修改,都不会影响到原始值。

但是,如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

  1. var obj = { p: 1 };
  2. function f(o) {
  3. o.p = 2;
  4. }
  5. f(obj);
  6. obj.p // 2

上面代码中,传入函数f的是参数对象obj的地址。因此,在函数内部修改obj的属性p,会影响到原始值。

注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。

  1. var obj = [1, 2, 3];
  2. function f(o) {
  3. o = [2, 3, 4];
  4. }
  5. f(obj);
  6. obj // [1, 2, 3]

上面代码中,在函数f()内部,参数对象obj被整个替换成另一个值。这时不会影响到原始值。这是因为,形式参数(o)的值实际是参数obj的地址,重新对o赋值导致o指向另一个地址,保存在原地址上的值当然不受影响。

同名的形参

如果有同名的参数,则取最后出现的那个值。

  1. function f(a, a) {
  2. console.log(a);
  3. }
  4. f(1, 2) // 2

上面代码中,函数f()有两个参数,且参数名都是a。取值的时候,以后面的a为准,即使后面的a没有值或被省略,也是以其为准。

  1. function f(a, a) {
  2. console.log(a);
  3. }
  4. f(1) // undefined

调用函数f()的时候,没有提供第二个参数,a的取值就变成了undefined。这时,如果要获得第一个a的值,可以使用arguments对象。

  1. function f(a, a) {
  2. console.log(arguments[0]);
  3. }
  4. f(1) // 1