函数
一般来说,一个函数是可以通过外部代码调用的一个“子程序”(或在递归的情况下由内部函数调用)。像程序本身一样,一个函数由称为函数体的一系列语句组成。值可以传递给一个函数,函数将返回一个值。在 JavaScript 中,函数是头等 (first-class)对象,因为它们可以像任何其他对象一样具有属性和方法,可以像其他数据类型一样被赋值给变量、作为参数传递给其他函数,甚至作为其他函数的返回值。它们与其他对象的区别在于函数可以被调用。简而言之,它们是Function对象。 ——MDN
声明和调用
函数可以把具有相同或相似逻辑的代码“包裹”起来,通过函数调用执行这些被“包裹”的代码逻辑,这么做的优势是有利于精简代码方便复用。
声明(定义)
声明(定义)一个完整函数包括关键字、函数名、形式参数、函数体、返回值5个部分
调用
声明(定义)的函数必须调用才会真正被执行,使用 ()
调用函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数声明和调用</title>
</head>
<body>
<script>
// 声明(定义)了最简单的函数,既没有形式参数,也没有返回值
function sayHi() {
console.log('Hi~')
}
// 函数调用,这些函数体内的代码逻辑会被执行
// 函数名()
sayHi()
// 可以重复被调用,多少次都可以
sayHi()
</script>
</body>
</html>
注:函数名的命名规则与变量是一致的,并且尽量保证函数名的语义。
参数
参数是在函数名后的圆括号内定义的,多个参数之间用逗号分隔。
通过向函数传递参数,可以让函数更加灵活多变,参数可以理解成是一个变量。
声明(定义)一个功能为打招呼的函数
- 传入数据列表
- 声明这个函数需要传入几个数据
- 多个数据用逗号隔开
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数参数</title>
</head>
<body>
<script>
// 声明(定义)一个功能为打招呼的函数
// function sayHi() {
// console.log('Hi~')
// }
// 调用函数
// sayHi()
// 这个函数似乎没有什么价值,除非能够向不同的人打招呼
// 这就需要借助参数来实现了
function sayHi(name) {
// 参数 name 可以被理解成是一个变量
console.log(name)
console.log('Hi~' name)
}
// 调用 sayHi 函数,括号中多了 '小明'
// 这时相当于为参数 name 赋值了
sayHi('小明')// 结果为 小明
// 再次调用 sayHi 函数,括号中多了 '小红'
// 这时相当于为参数 name 赋值了
sayHi('小红') // 结果为 小红
</script>
</body>
</html>
总结:
- 声明(定义)函数时的形参没有数量限制,当有多个形参时使用
,
分隔 - 调用函数传递的实参要与形参的顺序一致
形参和实参
形参(Formal Arguments)
形参是在定义函数时,在函数名后的括号内指定的占位符变量。它们代表函数期望接收的值,但并不实际包含值。形参的作用是告诉调用者这个函数需要哪些信息才能执行其任务。例如:
代码语言:javascript复制function addNumbers(a, b) {
return a b;
}
在这个例子中,a 和 b 是形参,它们代表了将来调用该函数时需要提供的两个数值。
实参(Actual Arguments)
实参是当函数被调用时,实际传递给函数的具体值。这些值用来替换函数定义中的形参。继续上面的例子,当我们调用 addNumbers 函数时,传递的值就是实参:
代码语言:javascript复制let result = addNumbers(5, 3);
这里,5 和 3 就是实参,它们分别对应并赋值给形参 a 和 b,函数执行后返回它们的和。
形参与实参的关系
- 匹配:实参的数量和类型应当与函数定义中的形参相匹配。如果数量不匹配,JavaScript 在严格模式下会抛出错误;如果不使用严格模式,则可能会导致意外的行为或错误。
- 传递方式:JavaScript 中,实参向形参的传递是基于值的传递。对于原始类型(如数字、字符串、布尔值),传递的是值的副本;而对于引用类型(如对象、数组),传递的是引用的副本,这意味着函数内部可以修改对象的属性或数组的内容,影响到外部。
- 默认参数:ES6 引入了默认参数功能,允许在定义函数时为形参指定默认值。如果调用函数时没有提供对应的实参,就使用默认值。
function greet(name = "User") {
console.log(`Hello, ${name}!`);
}
greet(); // 输出 "Hello, User!"
greet("Alice"); // 输出 "Hello, Alice!"
eg:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数参数</title>
</head>
<body>
<script>
// 声明(定义)一个计算任意两数字和的函数
// 形参 x 和 y 分别表示任意两个数字,它们是两个变量
function count(x, y) {
console.log(x y);
}
// 调用函数,传入两个具体的数字做为实参
// 此时 10 赋值给了形参 x
// 此时 5 赋值给了形参 y
count(10, 5); // 结果为 15
</script>
</body>
</html>
返回值
return
语句用于从函数中退出并返回一个值给调用者。如果函数体中没有return
语句,或者return
后面没有值,那么函数默认返回undefined
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数返回值</title>
</head>
<body>
<script>
// 定义求和函数
function count(a, b) {
let s = a b
// s 即为 a b 的结果
// 通过 return 将 s 传递到外部
return s
}
// 调用函数,如果一个函数有返回值
// 那么可将这个返回值赋值给外部的任意变量
let total = count(5, 12)
</script>
</body>
</html>
总结:
- 在函数体中使用return 关键字能将内部的执行结果交给函数外部使用
- 函数内部只能出现1 次 return,并且 return 下一行代码不会再被执行,所以return 后面的数据不要换行写
- return会立即结束当前函数
- 函数可以没有return,这种情况默认返回值为 undefined
作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域
- 定义:在代码的最外层定义的变量或函数拥有全局作用域,这意味着它们在整个代码中任何地方都是可访问的。
- 特点:全局变量会一直存在,直至页面关闭,可能导致内存泄漏。尽量避免非必要地使用全局变量,因为它们容易引起命名冲突。
let globalVar = "I'm global!";
function test() {
console.log(globalVar); // 访问全局变量
}
test(); // 输出 "I'm global!"
局部作用域
- 定义:在函数内部定义的变量拥有局部作用域,只能在该函数内部访问。
- 特点:每次函数调用时都会创建新的局部作用域,变量在函数执行结束后会被销毁,有助于资源管理。
function test() {
let localVar = "I'm local!";
console.log(localVar); // 访问局部变量
}
test(); // 输出 "I'm local!"
console.log(localVar); // 错误,localVar在此不可访问
注意:
- 如果函数内部,变量没有声明,直接赋值,也当全局变量看,但是强烈不推荐,这种行为经常导致意料之外的错误和全局变量的污染。
- 函数的形参(形式参数)在函数定义时自动被视为局部变量。
匿名函数
匿名函数,顾名思义,是没有名字的函数。在JavaScript中,匿名函数是一种非常灵活且常用的特性,常用于需要一次性使用的简短函数逻辑场景,或是作为其他函数的参数传递给高阶函数。
函数表达式
函数表达式将函数定义赋值给一个变量、对象的属性或作为参数传递给其他函数。它可以是命名的也可以是匿名的。
代码语言:javascript复制// 声明
let fn = function() {
console.log('函数表达式')
}
// 调用
fn()
函数表达式在赋值操作完成之前不能被调用,因为它们属于普通变量的赋值,遵循变量声明的规则。
立即执行函数
立即执行函数(IIFE,Immediately Invoked Function Expression),即立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数。
代码语言:javascript复制(function(){ xxx })();
(function(){xxxx}());
//eg:
(function() {
console.log("这是一个匿名函数,并且立即被执行了!");
})();
注意:
- 无需调用,立即执行,其实本质已经调用了
- 多个立即执行函数之间用分号隔开