函数的基础语法

函数是 JavaScript 中一个非常重要的概念。里面涉及到的知识点也比较多,这里我们先讲一下函数的一些基本用法。

函数的定义

JavaScript 中创建函数的方式分为三种:

  • 声明式函数
  • 函数表达式
  • 构造函数

其中第三种通过调用构造函数new Function()来创建函数的方式并不实用,所以这里我们只介绍另外两种常用的。

声明式函数

“声明式函数”是通过关键字 function 加上函数名来创建一个函数。语法结构如下:

1
2
3
function 函数名() {
// 函数内部要执行代码
}

函数表达式

”函数表达式“是将一个没有名字的函数赋值给一个变量,变量名就作为函数名使用。语法结构如下:

1
2
3
let 函数名 = function() {
// 函数内部要执行代码
}

函数的调用

函数创建好后内部的代码并不会执行。因为函数的创建仅仅只是封装好了一个功能,要使用功能还需要对函数进行调用。

不管采用什么方式创建函数,调用的方法都是一样的。语法结构如下:

1
函数名()

例:

1
2
3
4
function foo() {
console.log("hello foo");
}
foo(); // 调用函数 foo

函数的返回值

返回值是指可以将函数内部的一个值返回到函数外部去。

设置返回值

在函数体内部,通过return关键字来设置返回值。

1
2
3
4
function foo() {
let num = 100;
return num;
}

上例中,num就是函数foo的返回值。也就是说,我们将函数内部的数据 100 返回到了函数外部。

接收返回值

函数内部将数据return出来,外部还需要先接收才能使用。而外部接收返回值的地方就是函数的调用。

1
console.log(foo()); // 100

也就是说,使用函数名()其实有两个功能:一是调用函数执行函数内部代码,二是接收函数内部的返回值。

return 特点

  • 设置返回值并不是必须的。当函数内没有定义returnreturn后面没有值时,当前函数的返回值默认为undefined

    1
    2
    function bar() {};
    console.log(bar()); // undefined
  • 如果设置返回值,return语句后面只能跟一个值。如果要返回多条数据时,只能考虑将其合并成一个整体(例如:数组)。

    1
    2
    3
    4
    5
    6
    function bar() {
    let a = 1;
    let b = 2;
    let c = 3;
    return [a, b, c];
    }
  • return语句一旦执行完毕,会立即结束当前函数,即函数内return后面的语句不会再执行。

    1
    2
    3
    4
    5
    function bar() {
    let a = 1;
    return a;
    console.log(a); // 不会执行
    }

函数的参数

函数的参数可以看做是在函数内部使用的局部变量。

形参和实参

一个完整的函数参数由两部分组成:

  • 形参:形式参数,指在创建函数时定义的参数(类似于局部变量名)。
  • 实参:实际参数,指在调用函数时定义的参数(类似于局部变量值)。

语法结构如下:

1
2
function foo(形参1, 形参2, ..., 形参n) {}; // 创建函数
foo(实参1, 实参2, ..., 实参n); // 调用函数

当函数调用时,会将实参传递给对应位置的形参,效果类似于变量赋值。

例:

1
2
3
4
function bar(num1, num2) {
console.log(num1, num2); // 100 200
}
bar(100, 200);

一般情况下,形参和实参的个数是相同的,这样就能一一对应进行传值操作。但在 JavaScript 中并不强求这一点,在特殊情况下,函数的形参和实参的个数可以不相同。

例如:

1
2
3
4
function bar(num1) {
console.log(num1); // 1
}
bar(1, 2, 3);

在上例中,形参num1接收到了实参1。但是实参23因为没有对应的形参接收,因此函数内部是找不到这两条数据的。

arguments 对象

函数中除了可以用形参来接收实参外,还可以用函数内部的 arguments 对象来接收所有的实参。

1
2
3
4
function bar() {
console.log(arguments); // { '0': 100, '1': 200, '2': 300 }
}
bar(100, 200, 300);

arguments 是一个伪数组对象,它也可以通过下标来单独访问里面每一条数据。

1
2
3
4
5
6
function bar() {
console.log(arguments[0]); // 100
console.log(arguments[1]); // 200
console.log(arguments[2]); // 300
}
bar(100, 200, 300);

不定参数

关于函数的参数,ES6 中增加了一个新的特性,叫做 rest 参数,即“不定参数”。它的作用和 arguments 对象很类似,arguments 是用来接收所有的实参,rest 是用来接收没有形参对应的所有实参。

语法结构:

1
function foo(...不定参数名) {};

例:

1
2
3
4
function foo(...nums) {
console.log(nums); // [ 100, 200, 300 ]
}
foo(100, 200, 300);

在上例中,因为三个实参都没有对应的形参,所以不定参数nums数组的形式接收了三个实参。

注意:不定参数可以和普通形参同时存在,但是不定参数只能作为最后一个形参使用。

1
2
3
4
5
function foo(num1, ...nums) {
console.log(num1); // 100
console.log(nums); // [ 200, 300 ]
}
foo(100, 200, 300);

当实参个数确定的情况下,我们用普通形参来接收实参;

当实参个数不确定的情况下,我们可以用 arguments 对象或者不定参数来接收实参。

默认参数

默认参数,指的是函数形参的默认值。当形参没有值时,就会采用默认值。

我们在调用函数时,难免会存在忘记传实参的情况。一旦忘记传实参,就有可能对我们函数内部的代码造成影响。所以,一般情况下,为了避免因为忘记传参而造成的代码运行错误,我们都会给形参一个默认值。这样,当我们没有传实参的时候,形参可以采用默认值。

在 ES6 之前,没有专门设置形参默认值的语法。而现在在 ES6 中,它已经自己提供了一个设置默认参数的功能。语法结构如下:

1
2
3
function foo(形参 = 默认值) {
// ...
}

例:

1
2
3
4
5
function foo(name = "HanMeiMei") {
console.log('hello ' + name);
}
foo(); // hello HanMeiMei
foo("LiZiMing"); // hello LiZiMing

参数的应用场景

函数的参数并不是必须的,那到底什么时候需要使用参数?

我们知道,封装函数的目的就是为了避免书写大量重复的代码。例如,我们要书写三个人的自我介绍的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function introduce1(){
console.log("你好");
console.log("我的名字叫韩梅梅");
console.log("性别女");
console.log("今年20岁");
}
introduce1();
function introduce2(){
console.log("你好");
console.log("我的名字叫马冬梅");
console.log("性别女");
console.log("今年30岁");
}
introduce2();
function introduce3(){
console.log("你好");
console.log("我的名字叫李子明");
console.log("性别男");
console.log("今年18岁");
}
introduce3();

在这三个方法中,存在大量重复的代码,按理说可以直接封装成一个函数。但是如果封装成一个函数,里面的姓名、年龄、性别又是不一样的,那这个时候怎么办?

1
2
3
4
5
6
7
8
9
function introduce(name, gender, age){
console.log("你好");
console.log("我的名字叫" + name);
console.log("性别" + gender);
console.log("今年" + age + "岁");
}
introduce("韩梅梅", "女", 20);
introduce("马冬梅", "女", 30);
introduce("李子明", "男", 18);

函数的参数就能很好的解决这个问题。所以,当封装好的重复代码中,有小部分内容是不重复的,那么就把这小部分作为函数的参数,通过调用函数时传入不同的实参来实现这小部分代码的不重复。

我 秦始皇 打钱