函数
一、声明和调用
函数可以把具有相同或相似逻辑的代码“包裹”起来,通过函数调用执行这些被“包裹”的代码逻辑,有利于精简代码方便复用。
1.声明(定义)
声明(定义)一个完整函数包括关键字、函数名、形式参数、函数体、返回值5个部分
2.调用
声明(定义)的函数必须调用才会真正被执行,使用 () 调用函数。
注意:函数名的命名规则与变量一致,并且尽量保证函数名的语义。
为什么用()可以调用函数?
使用括号 () 来调用函数是编程语言中的一种约定和语法规则。
从逻辑角度来看,括号用于表示对函数的“触发”或“激活”操作。当使用括号时,意味着告诉编程语言要执行这个函数定义中指定的一系列计算或操作。
从参数传递的角度,括号提供了一个位置来放置传递给函数的参数值。函数可能需要这些参数来进行具体的计算或处理,并根据传入的参数返回相应的结果。
这种约定使得编程语言的语法结构清晰、统一且易于理解和解析,程序员能够明确地表达他们希望执行特定函数的意图。
* 使用 () 调用函数主要有以下几个原因
-
标识执行动作:
()明确表示要执行函数内部定义的代码逻辑。 -
传递参数:如果函数定义时接收参数,通过在括号内提供参数值来传递给函数,以便函数根据这些参数进行相应的处理。
例如,如果有一个函数 function add(a, b) { return a + b; } ,可以通过 add(2, 3) 来调用并传递 2 和 3 作为参数。
- 符合语言语法规范:这是 JavaScript 语言本身定义的语法规则,大家都遵循这个规则来编写清晰、可理解和可维护的代码。
- 区分函数和函数的引用:当没有括号时,例如只是提到函数名,它表示的是对函数的引用,而不是执行函数。只有加上括号才会真正执行函数。
二、参数
1.参数
通过向函数传递参数,可以让函数更加灵活多变,参数可以理解成是一个变量。
声明(定义)一个功能为打招呼的函数
- 传入数据列表
- 声明这个函数需要传入几个数据
- 多个数据用逗号隔开
总结:
- 声明(定义)函数时的形参没有数量限制,当有多个形参时使用
,分隔 - 调用函数传递的实参要与形参的顺序一致
2.形参和实参
形参:声明函数时写在函数名右边小括号里的叫形参(形式上的参数)
实参:调用函数时写在函数名右边小括号里的叫实参(实际上的参数)
形参可以理解为是在这个函数内声明的变量(比如 num1 = 10)实参可以理解为是给这个变量赋值
开发中尽量保持形参和实参个数一致,若不一致则有以下情况:
-
实参数量多于形参数量:
- 多余的实参可以通过
arguments对象来获取。arguments对象是一个类数组对象,它包含了函数调用时传递的所有实参。
- 多余的实参可以通过
-
实参数量少于形参数量:
- 未被对应实参赋值的形参将被赋予
undefined值。
- 未被对应实参赋值的形参将被赋予
arguments是什么?
arguments 是一个类数组对象,它在函数内部可用。
arguments 对象包含了函数被调用时传入的实际参数。
它具有以下特点:
- 类数组结构:具有
length属性表示参数的数量,可以通过索引(如arguments[0]、arguments[1]等)来访问每个参数的值。 - 非真正的数组:它没有数组的方法,如
push、pop等,但可以通过一些方法将其转换为真正的数组进行操作。 - 实时反映参数变化:如果在函数内部修改了参数的值,
arguments对象中的对应值也会随之改变。
需要注意的是,在 ES6 的箭头函数中没有 arguments 对象。
三、返回值
函数的本质是封装(包裹),函数体内的逻辑执行完毕后,函数外部将通过 return 这个关键字获得函数内部的执行结果,这个被传递到外部的结果就是返回值。
<script>
function count(a, b) {
let s = a + b
// 通过 return 将 s 传递到外部
return s
}
// 调用函数,如果一个函数有返回值
// 那么可将这个返回值赋值给外部的任意变量
let total = count(5, 12)
</script>
总结:
- 在函数体中使用return 关键字能将内部的执行结果交给函数外部使用
- 函数内部只能出现1 次 return,并且return 下一行代码不会再被执行,所以return 后面的数据不要换行写,这是由 JavaScript 语言的设计和执行机制决定的。
- return会立即结束当前函数
- 函数可以没有return,这种情况默认返回值为 undefined
- 在异步操作中,比如使用
async/await时,throw语句用于抛出错误,类似于return提前终止操作并返回异常。
如何返回多个数据?
- 使用对象:将多个数据组合成一个对象并返回。
<script>
function getData() {
return {
name: "John",
age: 30,
city: "New York"
};
}
</script>
- 使用数组:把多个数据放入一个数组中返回。
<script>
function getData() {
return [10, 20, 30];
}
</script>
- 使用 ES6 的解构赋值:如果返回的是一个数组或对象,可以在调用函数时进行解构赋值来获取多个值。
<script>
function getData() {
return [10, 20, 30];
}
let [a, b, c] = getData();
</script>
<script>
function getData() {
return { num1: 5, num2: 10 };
}
let { num1, num2 } = getData();
</script>
四、作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
1.全局作用域
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件
处于全局作用域内的变量,称为全局变量
2.局部作用域
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
处于局部作用域内的变量称为局部变量
注意:如果函数内部,变量没有声明,直接赋值,也当全局变量看,但不建议使用,原因如下:
- 意外的变量覆盖:可能会意外覆盖同名的全局变量,导致难以调试的错误。
- 代码可读性和可维护性差:其他开发者阅读代码时,可能难以理解变量的作用域和预期行为。
- 不利于模块化和封装:良好的编程实践通常鼓励将函数内部的逻辑封装起来,避免对全局作用域造成不必要的影响。
- 潜在的命名冲突:在复杂的项目中,特别是多个文件和模块组合在一起时,未声明的全局变量更容易导致命名冲突。