函数
函数:function,是被设计为执行特定任务的代码块。
说明:函数可以把具有相同或相似逻辑的代码“包裹”起来,通过函数调用执行这些被“包裹”的代码逻辑,这么做可以实现代码复用,提高开发效率。
1、函数使用
1.1 函数的基本使用语法
function 函数名() {
函数体
//函数体是函数的构成部分,它负责将相同或相似代码“包裹”起来直到函数调用时函数体内的代码才会被执行。函数的功能代码都要写在函数体当中。
}
函数名()
例:
// 1. 函数的声明
function sayHi() {
document.write(`你好~~~`)
}
// 2. 函数调用
//注意:声明(定义)的函数必须调用才会真正被执行,使用 () 调用函数
sayHi()
1.2 函数的命名规范
- 和变量命名基本一致
- 尽量小驼峰命名法
- 前缀应该为动词
- 命名建议:常用动词约定
function getName() {}
function addSquares() {}
2.函数传参
2.1 为什么要有参数的函数
大家看下面这个函数:
function getSum() {
let num1 = 10
let num2 = 20
console.log(num1 + num2)
}
getSum()
思考:大家可以看出这样的函数只能求 10 + 20, 这个函数功能局限非常大
解决方法:要把计算的数字传到函数内
结论:若函数的完成功能需要调用者传入数据,那么就需要用有参数的函数
2.2 有参数的函数声明和调用
声明语法:
function 函数名(参数列表) {
//参数列表:传入数据列表;声明这个函数需要传入几个数据;多个数据之间用逗号隔开
函数体
}
函数名(传递的参数列表)
单个参数
function getSum(num1) {
document.write(num1 *num1)
}
getSum(9)
多个参数
function getSum(num1,num2) {
document.write(num1 + num2)
}
getSum(10,20)
形参:声明函数时写在函数名右边小括号里的叫形参(形式上的参数)
实参:调用函数时写在函数名右边小括号里的叫实参(实际上的参数)
建议:开发中尽量保持形参和实参个数一致
2.3 函数练习
- 求 1~100的累加和 封装函数
function getSum100() {
let sum = 0
for (let i = 1; i <= 100; i++) {
sum += i
}
document.write(sum)
}
getSum100()
- 调用函数的时候传入两个实参,求两实参之间的累加和
function getSum100(start, end) {
let sum = 0
for (let i = start; i <= end; i++) {
sum += i
}
document.write(sum)
}
getSum100(1, 10)
getSum100(10, 100)
- 拓展 函数封装求和
return 返回值会在接下来的内容中详细介绍
合理利用逻辑中断,解决 形参如果不被赋值,就是 undefined 的问题
function getSum(x, y) {
x = x || 0
//如果 x 的布尔值为 true,则把 右边的x 赋值给 左边的x ,否则把 0 赋值给 x
y = y || 0
// 先计算 x + y 再返回
return x + y
}
let sum = getSum(1, 2)
// let num1 = prompt('请输入')
document.write(sum)
4.函数封装-求学生总分
<script>
// 需求:学生的分数是一个数组,计算每个学生的总分
// 分析:
// (1) 封装一个求和函数
// (2) 传递过去的参数是一个数组
// (3)函数内部遍历数组求和
function getScore(arr) {
// arr = [99, 10, 100]
let sum = 0
for (let i = 0; i < arr.length; i++) {
sum += arr[i]
}
document.write(sum)
}
// 调用函数
getScore([88, 99, 100])
getScore([90, 80, 100])
</script>
3.函数返回值
3.1为什么要让函数有返回值
函数内部不需要输出结果,而是返回结果
我们前面已经接触了很多的函数具备返回值:
let result1 = prompt('请输入您的年龄")
let result2 = parseInt('111')
只是这些函数是JS内置的,我们直接就可以使用
当然有些函数就没有返回值例如 alert()
所以根据需求来设定需不需要返回值。
3.2 用return返回数据
当函数需要返回数据出去时,用return关键字
基本使用:
function getSum(x, y) {
return x + y
}
let num =getSum(10,30)
document.write(num)
3.3 函数返回值的细节
- 在函数体中使用 return 关键字能将内部的执行结果交给函数外部使用
- 函数内部只能出现 1 次 return,并且 return 后面代码不会再被执行,所以 return 后面的数据不要换行写
- return会立即结束当前函数
- return后面不接数据或者函数内不写return,函数的返回值是undefined
3.4函数返回值练习
<script>
// 求数组最大值的函数
function getArrMaxValue(arr) {
// 声明一个max变量
// 把数组第一个值给 max
let max = arr[0]
// 开始遍历数组并比较
for (let i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i]
}
}
// 返回这个最大值
return max
}
let maxplus = getArrMaxValue([1, 5, 8, 9, 3])
document.write(`数组的最大值是${maxplus}`)
</script>
4.作用域
4.1作用域的概述
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围
就是这
个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
4.2 变量的作用域
在JavaScript中,根据作用域的不同,变量可以分为 全局变量
、局部变量
和块级变量
4.2.1 全局变量
//1.全局变量 全局能用
let num = 10
console.log(num) //10
function fn() {
console.log(num)
}
fn() //10
4.2.2 局部变量
大坑: 局部变量必须是函数里面声明过(let)的变量
// 2. 在局部作用域下,变量是 局部变量
// 函数内的变量,只能给内部使用,函数外面不能使用
function fn() {
let num = 20
console.log(num)
function fn1() {
console.log(num)
let num2 = 30
}
fn1()
// console.log(num2) // 控制台输出结果: num2 is not defined
}
fn()
console.log(num) //控制台输出结果: num is not defined
4.2.3 块级变量
let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问
for (let i = 0; i < 5; i++) {
console.log(i)
}
console.log(i) //控制台报错:Uncaught ReferenceError: i is not defined
4.3 变量访问原则-作用域
变量访问原则:在能够访问到的情况下 先局部 局部没有在找全局
作用域链:根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访
问,就称作作用域链
4.3.2 变量访问原则-作用域 (小练习)
// 作用域链:采取就近原则的方式来查找变量最终的值
let a = 1
function fn1() {
let a = 2
let b = '22'
fn2()
function fn2() {
let a = 3
fn3()
function fn3() {
let a = 4
console.log(a) //a的值 4
console.log(b) //b的值 22
}
}
}
fn1()
5.匿名函数
函数可以分为 具名函数
和 匿名函数
// 声明
function fn() {
}
//调用
fn()
匿名函数 :将匿名函数赋值给一个变量,并且通过变量名称进行调用 我们将这个称为函数表达式
let fn = function () {
//函数体
}
fn() //函数名
//其中函数的形参和实参使用跟具名函数一致
5.1立即执行函数
场景介绍:避免全局变量之间的污染
多个立即执行函数要用 ; 隔开,要不然会报错
// 立即执行函数 立即执行, 无需调用
//方式一:
(function () {console.log(111)})();
//方式二:
(function () {console.log(111)}());
//注意: 多个立即执行函数要用 ; 隔开,要不然会报错
// 第一个小括号放的 形参 第二个小括号放的是实参
(function (x, y) {
console.log(x + y)
})(1, 2)
6.综合案例
<script>
//需求: 用户输入秒数,可以自动转换为时分秒
//分析:
//(1): 用户输入总秒数
//(2):计算时分秒(封装函数) 里面包含数字补0
//(3):打印输出
// 1. 用户输入
let second = +prompt('请输入总的秒数:')
// 2. 计算时间 封装函数
function getTimes(t) {
// 小时: h = parseInt(总秒数 / 60 / 60 % 24)
// 分钟: m = parseInt(总秒数 / 60 % 60)
// 秒数: s = parseInt(总秒数 % 60)
let h = parseInt(t / 60 / 60 % 24)
let m = parseInt(t / 60 % 60)
let s = parseInt(t % 60)
h = h < 10 ? '0' + h : h
m = m < 10 ? '0' + m : m
s = s < 10 ? '0' + s : s
return `计算之后的时间是${h}小时${m}分${s}秒`
}
// 3. 打印输出
let str = getTimes(second)
document.write(str)
// document.write(str)
</script>
7.自问自答
1.函数不调用会执行吗?如何调用函数?
答:函数不调用自己不执行,调用方式:函数名()
2.函数的复用代码和循环复用代码有什么不同?
函数的复用代码随时调用,随时执行,可重复调用
循环代码写完即执行,不能很方便的控制执行位置
3. 函数参数可以分为那两类?怎么判断他们是那种参数?
函数可以分为形参和实参
- 函数声明时,小括号里面的是形参,形式上的参数
- 函数调用时,小括号里面的是实参,实际的参数
- 尽量保持形参和实参的个数一致
4. 为什么要让函数有返回值
- 函数执行后得到结果,结果是调用者想要拿到的(函数内部不需要输出结果,而是返回结果)
- 对执行结果的扩展性更高,可以让其他的程序使用这个结果
5. JS 中作用域分为哪三种?
- 全局作用域。函数外部或者整个script 有效
- 局部作用域。也称为函数作用域,函数内部有效
- 块级作用域。 { } 内有效
6. 变量访问原则是什么?
作用域链:采取就近原则的方式来查找变量最终的值
7.立即执行函数需要调用吗? 有什么注意事项呢?
- 无需调用,立即执行,其实本质已经调用了
- 多个立即执行函数之间用分号隔开