‌JavaScript中的函数(Function)(第7节)


在网页交互和程序前后端开发中,经常会在多个地方使用相同的代码段。这时候,我们可以把这一段代码封装成一个函数,这样就可以在程序中多次调用这个函数,而不必重复编写相同的代码。函数的运用不仅可以减少代码量,还可以提高代码的可读性、可维护性和可测试性。

1、函数的概念及运用

在JavaScript中,函数是一段可重复使用的代码块,用于封装具有相同或相似逻辑的代码。通过此代码块可以实现大量代码的重复使用。

(1)函数的定义

第一种方法:通过“函数声明”定义函数

在JavaScript中,可以通过function关键字来定义函数。函数可以接受参数并返回值。注意,函数声明后并不会自动执行函数体中的代码,需要通过函数名调用后才会执行函数体中的代码。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            // 声明add()函数
            function add(a, b) {
            return a + b;
            }

            // 调用函数,并将函数的返回值赋值给变量“sum”
            sum = add(1, 5)
            console.log(sum); // 输出: 6
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

6

上面的例子中,我们声明了一个简单的add()函数,并接受两个参数a和b,然后返回它们的和。接着,我们通过函数名add(1, 5)调用函数并传入两个参数,最后将函数的返回值赋值给变量“sum”。注意,函数的声明"function" 这个词必须是小写的,否则JavaScript就会出错。另外,必须使用大小写完全相同的函数名来调用函数。

第二种方法:通过“函数表达式”定义函数

在JavaScript中,由于函数也是一种数据类型,所以可以通过表达式来定义函数。将函数体直接赋值给一个变量,并且通过变量名称进行调用函数。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            // 用一个变量来接收函数
            let add = function(a, b){
            return a + b;
            }

            // 调用函数,并将函数的返回值赋值给变量“sum”
            sum = add(1, 5)
            console.log(sum); // 输出: 6
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

6

第三种方法:通过“箭头函数”定义函数

在JavaScript中,还可以通过箭头函数简化函数定义。它使用“=>”符号,提供了一种更简洁的方式来定义函数。

箭头表达式的基本语法:

(参数1, 参数2, ..., 参数N) => 函数体代码
  • 如果只有一个参数,括号可以省略:参数 => 函数体代码。

  • 如果没有参数,必须用空括号:() => 函数体代码。

  • 如果“函数体中的代码”包含多行,则必须使用大括号“{}”,且需要一个显示的return语句。

箭头函数的示例如下:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            // 箭头函数写法
            let add = (a, b) => a + b;
            let sum = add(1, 5);
            console.log(sum); // 输出 6
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

6

在JavaScript中,箭头函数的语法比传统的匿名函数表达式更简洁,这使得代码更加清晰。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            // 传统的匿名函数
            setTimeout(function() { console.log("你好!"); }, 1000);

            // 箭头函数
            setTimeout(() => { console.log("再见!"); }, 2000);
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

你好
再见

上面的例子中,setTimeout()函数是JavaScript中的一个定时器函数,用于在指定的毫秒数后执行一次指定的函数或代码段。从两种函数的对比结果可以看出,箭头函数比函数表达式更简洁,所以更适用于那些本来需要匿名函数的地方,写法更简单。

(2)JavaScript函数的返回值和参数

‌返回值‌:‌函数可以通过return语句返回一个值。如果函数没有return语句,或者return语句没有指定值,那么函数将返回undefined。

‌参数‌:‌函数可以接受参数,也可以不接受任何参数,这些参数在函数体内可以像变量一样使用。在函数声明中,参数被放在括号内,多个参数用逗号分隔。

‌形参‌:‌在函数声明时定义,用于接收调用时传递的参数。比如,函数声明function add(a, b) {}中,a和b就是两个形参。

‌实参‌:‌在函数调用时传递的值,传递给形参使用。比如,函数调用add(1, 5)中,1和5就是两个‌实参‌。

在JavaScript中,‌形参‌和‌实参‌的个数可以不一致。如果形参过多会自动填上“undefined”,如果实参过多,会忽略多余的实参。但实际写代码的时候尽量保持形参和实参的个数一致。

如果形参个数比实参个数多,则多出来的形参的值为“undefined”。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            function add(a, b, c){
                return a+b+c;
            }
            let sum = add(2, 3);
            console.log(sum); // 输出 NaN
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

NaN

上面的例子中,调用函数add(2, 3)时,传入的实参少了一个,默认会自动将第三个参数设置为undefined类型。undefined类型和‌Number‌‌数值型相加,结果为NaN。

如果实参个数比形参个数多,则多出来的实参不参与函数运算。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            function add(a, b, c){
                return a+b+c;
            }
            let sum = add(1, 2, 3, 4);
            console.log(sum); // 输出 6
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

6

(3)arguments对象

在调用函数时,如果我们不确定有多少个参数传递的时候,可以使用arguments来获取调用函数时传入的所有实参的值。arguments实际上是所有函数的一个内置对象。arguments对象是JavaScript中所有函数内都可以使用的类数组对象。它包含传递给该函数的所有参数,当调用函数时,通过arguments对象可以访问传递的参数,即使这些参数在函数声明中没有明确列出。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            function add(){
                console.log(arguments);
            }
            add(1, 2, 3, 4); // 输出: [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4}
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

3

上面的例子中,即使add()函数没有定义参数,arguments对象还是可以输出传递给它的所有参数。

arguments对象的访问方式与数组类似,可以通过索引获取传递的参数值,并可以通过length属性查看传递的参数数量。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            function add() {
                let sum = 0;
                for (let i = 0; i < arguments.length; i++) {
                    sum += arguments[i];
                }
                return sum;
                }
                console.log(add(1, 2, 3)); // 输出: 6
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

6

上面的例子中,我们使用arguments对象来累加传递给函数的参数。

2、变量的作用域

在JavaScript中,变量的作用域是指变量的可访问性的范围,如果超出该范围,在访问变量时就会出现错误。根据作用域的不同,我们将变量的作用域划分为全局作用域局部作用域块级作用域

(1)全局作用域

全局作用域在全局范围内有效,在代码的任何地方都可以访问。全局变量是在任何函数外定义的变量,它可以在代码的任何部分被访问。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            var jsVar = "这是全局变量";
            function showJsVar() {
                console.log(jsVar); // 可以访问全局变量
            }
            showJsVar(); // 输出: 这是全局变量
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

这是全局变量

上面的例子中,我们在函数外部使用var关键字声明了一个全局变量jsVar。这个变量在整个程序中都是可访问的,包括函数内部和外部。

如果在函数外部不使用var关键字来声明变量,那么这个变量也会被视为全局变量。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            jsVar = "这是全局变量";
            function showJsVar() {
                console.log(jsVar); // 可以访问全局变量
            }
            showJsVar(); // 输出: 这是全局变量
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

这是全局变量

上面的例子中,我们没有使用var关键字来声明变量jsVar,这也导致jsVar成为了一个全局变量

我们还可以使用window对象来声明一个全局变量。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            window.jsVar = "这是全局变量";
            function showJsVar() {
                console.log(jsVar); // 可以访问全局变量
            }
            showJsVar(); // 输出: 这是全局变量
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

这是全局变量

上面的例子中,我们在window对象上添加了一个新的属性jsVar,这个属性也可以视为一个全局变量

在实际开发中,应尽量避免使用全局变量,因为全局变量可能会在不经意间修改或覆盖全局命名空间,容易引起命名冲突。

(2)局部作用域

局部作用域是在函数内部定义的,只能在函数内部访问。局部变量包括函数参数和在函数内部使用var、let或const定义的变量。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            function test() {
                var localVar = "这是局部变量";
                console.log(localVar);
            }
            test(); // 输出 这是局部变量
            console.log(localVar); // 报错:localVar is not defined
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

这是局部变量
localVar is not defined

(3)块级作用域

在JavaScript中,使用“{}”包裹的代码我们称为代码块(如 if、for、while等)。块级作用域是指变量在声明它们的代码块内部有效,外部无法访问。块级变量包括在代码块内部使用var、let或const定义的变量。例如:

动手练一练:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>‌JavaScript中的函数示例</title>
</head>
<body>
    <body>
        <script>
            if (true) {
                let jsBlock = "这是块级变量";
                console.log(jsBlock); // 可以访问块级变量,输出 这是块级变量
            }
            console.log(jsBlock); // 报错:jsBlock is not defined
        </script>
    </body>
</html>

通过浏览器执行以上代码,我们按F12键打开浏览器的控制台,可以看到输出结果为:

这是块级变量
jsBlock is not defined

上面的例子中,jsBlock是块级变量,只能在声明它的if语句块内部访问。