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