1.函数
1.为什么使用函数?
如果想要多打印昨天案例中的九九乘法表该怎么做呢?难道把那么多代码多复制几遍吗?
接下来体验函数的魅力:代码的复用。
2.函数的使用
函数:
function 是可以执行特定任务的代码块。
本质上是把已经写好的 代码封装起来 再进行调用就可以重复使用这些代码。
这样做有利于精简我们的代码提高效率。
函数的语法:
function
function 函数名() {
函数体
}
函数名的命名规范同变量的一样 但是开头应该用动词 比如:get 得到 set 设置 say 说等
函数调用的语法:
函数名()
注意:当函数声明时只有被调用了,才能执行里面的代码,并且可以重复调用
案例:
封装一个函数,计算两个数的和
function getSum() {
let num1 = 10
let num2 = 20
console.log(num1 + num2)
}
getSum()
这样函数有什么缺陷?
可以发现在函数里面打印结果是很有局限性的 只能打印10和20的和 那么这就需要参数
参数声明语法:
function 函数名(参数列表) {
函数体
}
有参数的函数调用语法:
函数名(传递的参数列表)
例如:
<script>
function fn(num1, num2) {
document.write(num1 + num2) //30
}
fn(10, 20)
</script>
就是调用函数把10传给num1 把20传递给num2 执行函数体的代码,如果是多个数据中间用逗号隔开。
3.函数传参
形参和实参
像num1,num2 这种在声明函数小括号里面的叫形参,形式上的参数,
像10,20 这种在调用函数小括号里面的叫实参,实际上的参数。
形参可以理解为是在这个函数里面声明的变量,就如 let num1 = 10 所以形参也是局部变量后面会讲到。
实参可以理解为是在给这个形参赋值 把值给形参
尽量形参和实参的个数保持一致
逻辑中断在函数中的使用:
function getSum(num1, num2) {
// 利用逻辑中断让代码更完美 如果用户不传递任何数据就是undefined 就默认0
num1 = num1 || 0
num2 = num2 || 0
console.log(num1 + num2);
}
getSum()
// 更好用的方法:
// ES6新出的给函数的参数添加了默认值 来解决当用户不传参时让num1 和num2 默认值0
// 当有多个形参列表,默认值应放在形参列表的最后面 a 如果是默认值
function getSum(num1 = 0, num2 = 0, a) {
return num1 + num2
}
getSum()
undefined 表示未定义的数
undefined + undefined = NaN
Number(null) //null转换成数字类型为0
null 表示空的 所以是0
null + null = 0
案例:
需求:学生的分数是一个数组,计算每个学生的总分
<script>
// 声明一个数组
function getSum(arr) {
// 声明一个变量 和 的变量
let sum = 0
// 遍历数组
for (let i = 0; i < arr.length; i++) {
sum += arr[i]
}
document.write(sum) //217
}
// 调用函数 随便写一组数组
getSum([12, 42, 22, 6, 83, 52])
</script>
这几个案例把输出结果都写在函数体里面,就不够灵活 哪能写到函数体的外面吗?
4.函数的返回值
当函数执行完并不需要内部输出,而是应该把结果返回给调用者任他怎么使用结果,满足用户
返回值语法:
return 返回值
function getSum(num1, num2) {
return num1 + num2 //30
}
// 在外面接收 声明一个变量
let sum = getSum(10, 20)
document.write(sum)
注意一些细节:
- return可以将内部执行的结果返回给调用者
- 函数内部只能使用一次return,并且return后面的代码不再执行,直接退出整个函数,所以return后面不能换行
- return也可以省略,当没有return时此时的函数返回值是undefined
案例:
1. 求任意数组中的最大值并返回这个最大值和最小值
2. 求任意2个数中的最大值, 并返回
<script>
案例1
function getMaxAndMin(arr) {
// 声明一个最大值和最小值把数组的第一个元素赋值给它 让其与此后面的元素相比较
let max = arr[0]
let min = arr[0]
// 遍历数组 因为把一个元素给了最大/小值所以i从1开始
for (let i = 1; i < arr.length; i++) {
// 第一个元素与第二个元素比较 如果后面的大于这个最大值就把这个值给这个最大值
if (max < arr[i]) {
max = arr[i]
}
// 两个判断条件而不是写在一个if语句里面
if (min > arr[i]) {
min = arr[i]
}
}
// 返回值 返回数组形式就得到最大值和最小值
return [max, min]
}
// 调用函数 随便写一组数组 声明一个变量接收结果打印出来
let result = getMaxAndMin([12, 42, 22, 6, 83, 52])
document.write(result) //83,6
案例2:
// 声明函数 和两个形参
function getMax(num1, num2) {
return num1 > num2 ? num1 : num2
}
// 调用函数 赋值给一个变量打印结果
let result = getMax(12, 8)
console.log(result) //12
</script>
5.作用域
作用域就是一段代码限制在哪里可以使用的区域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
作用域分为全局作用域、局部作用域、块级作用域
- 全局作用域就是整个script便签里都可以使用,全局都有效
- 局部作用域就是在函数里使用,也叫做函数作用域,局部有效
- 块级作用域就是在{} 里面的像if for 语句里面使用,{}里有效
因为有作用域的存在,那么变量也分为全局变量、局部变量、块级变量
- 全局变量就是let在外部声明的变量,在全局作用域里都可以访问
- 局部变量就是在函数内部声明的变量,在函数的内部才能访问
- 块级变量只能在{}里使用和访问,跨块和跨函数都是不可以的
函数的形参是局部变量 因为形参就相当于在函数的内部声明了这个变量。
6.匿名函数
将匿名函数赋值给一个变量,并且通过变量名称进行调用 我们将这个称为函数表达式
语法:
let fn function() {
//函数体
}
fn() //函数的调用
到以后面的webAPI时会使用到匿名函数。
综合案例:
需求: 用户输入秒数,可以自动转换为时分秒,并能满足不为10的数补0
<script>
// format //格式化 dataFormat
// 1.准备一个变量接收用户输入的秒数
let time = +prompt('请输入秒数')
// 2.定义一个函数用于将用户输入的时间转换为时分秒
function dataFormat(t) {
let h = parseInt(t / 60 / 60 % 24)
let m = parseInt(t / 60 % 60)
let s = parseInt(t % 60)
// 调用补零函数体
h = padZero(h)
m = padZero(m)
s = padZero(s)
// 4. 返回结果
return `计算后的时间是${h}小时${m}分${s}秒`
}
// 3.补零
// 封装补零函数
function padZero(n) {
return n < 10 ? '0' + n : n
}
// 注意调用函数里面的实参就是用户输入结果,用time变量接收
let res = dataFormat(time)
document.write(res)
</script>