函数的作用是具有相同或相似逻辑的代码抽取出进行封装,执行特定任务的代码块(复用)。
比如我们前面使用的 alert()
、prompt()
和 console.log()
都是一些js 函数,只不过已经封装好了,我们直接使用的。
具名函数
<script>
// 函数声明
function sayHi() {
console.log('嗨~~~');
}
// 调用2次,可以任意调用
sayHi()
sayHi()
</script>
<script>
// 函数声明 函数名 sheet99()
function sheet99() {
// 还是九九乘法表
for (let i = 1; i <= 9; i++) {
for (let j = 1; j <= i; j++) {
document.write(`<span> ${j} X ${i} = ${i * j}</span>`)
}
document.write('<br>')
}
}
// 调用2次,可以任意调用
sheet99()
sheet99()
</script>
函数名命名规范
和变量命名基本一致
尽量小驼峰式命名法
前缀应该为动词
动词 | 含义 |
can | 判断是否可执行某个动作 |
has | 判断是否含义某个值 |
is | 判断是否为某个值 |
get | 获取某个值 |
set | 设置某个值 |
load | 加载某些数据 |
函数传参
思考:这样的函数只能求10+20,这个函数功能局限非常大!
办法:把要计算的数字传到函数内。若函数完成功能需要调用者传入数据,那么就需要用有参数的函数。
形参:声明函数时写在函数名右边小括号里的叫形参(形式上的参数)
实参:调用函数时写在函数名右边小括号里的叫实参(实际上的参数)
形参可以理解为是在这个函数内声明的变量(比如
num1= 10
)实参可以理解为是给这个变量赋值
<script>
// 调用()里叫形参,可以随意传单个或多个参值,相当在这个函数内声明的变量
// 1. start = 1 ; end = 50
// 2. start = 20 ; end = 100
// 3. start = 105
function getSum(start, end) {
let sum = 0
for (let i = start; i <= end; i++) {
sum = sum + i
}
console.log(sum)
}
// 调用()叫实参,getSum(50)中数会传给上面封装的代码块,
getSum(1, 50) // 1275
getSum(20, 100) // 4860
getSum(105) // 也设置一个或多个参数,注意要逗号隔开
</script>
案例:函数封装求和
需求:采取函数封装的形式:输入2个数,计算两者的和,打印到页面中。
<script>
function getSum(num1, num2) {
document.write(num1 + num2)
}
getSum(1, 9) // 10
</script>
参数默认值
形参可以看做变量,但是如果一个变量不给值,默认是 undefined
(未知);
如果做用户不输入实参,则出现 undefined + undefined 结果是NaN
,我们可以改进下:
用户不输入实参,可以给形参默认值,可以默认为0,这样程序更严谨。
<script>
// 形参给个0,不管实参给不给值都能参与运算互不影响
function getSum(x = 0, y = 0) {
document.write(x + y)
}
getSum(1, 2) // 3
getSum(1) // 1
getSum() // 0
</script>
『案例』求学生总分
需求:学生的分数是一个数组,计算每个学生的总分,分析:
①: 封装一个求和函数
②: 传递过去的参数是一个数组
③: 函数内部遍历数组求和
<script>
// 如果函数封装的是数组,则形参可以是 arr = []
function getArrSum(arr = []) {
let sum = 0
for (let i = 0; i <= arr.length; i++) {
sum += arr[i]
}
console.log(sum)
}
getArrSum([1, 2, 3, 4, 5]) // 15
getArrSum([11, 22, 33, 44, 54]) // 164
getArrSum() // 0
</script>
实参可以是数组:
<script>
// 如果函数封装的是数组,则形参可以是 arr = []
function getArrSum(arr = []) {
let sum = 0
for (let i = 0; i <= arr.length; i++) {
sum += arr[i]
}
console.log(sum)
}
getArrSum([1, 2, 3, 4, 5]) // 15
getArrSum([11, 22, 33, 44, 54]) // 164
getArrSum() // 0
</script>
实参可以是变量:
<script>
function getArrSum(n = 0, m = 0) {
let sum = 0
for (let i = n; i <= m; i++) {
sum += i
}
console.log(sum)
}
let num1 = +prompt('请输入起始值:')
let num2 = +prompt('请输入结束值:')
getArrSum(num1, num2)
</script>
函数返回值
函数执行完特定任务之后,然后把结果给我们就叫函数返回值。当函数需要返回数据出去时,用return
关键字。
在函数体中使用 return 关键字能将内部的执行结果交给函数外部使用
return
后面代码不会再被执行,会立即结束当前函数,所以return
后面的数据不要换行写return
函数可以没有return
,这种情况函数默认返回值为undefined
<script>
// 函数的返回值设置为20
function fn() {
return 20
}
// 相当于 fn() = 20
console.log(fn())
// 类同 let re = prompt('请输入数字')
let re = fn()
document.write(re)
</script>
<script>
// 函数的返回值
function getTotalPrice(x, y) {
return x + y
}
// 变量 = 函数实参
let sum = getTotalPrice(1, 2)
document.write(sum)
</script>
案例:求数组中最大值和最小值
求任意2个数中的最大值,并返回
<script>
// 求最大值函数
function getMax(x, y) {
// 1大于2吗 ?对输出1 :不对输出2
return x > y ? x : y
}
let max = getMax(1, 2)
console.log(max);
</script>
求任意数组中的最大值并返回这个最大值
<script>
// 求r任意数组的最大值并返回
function getArrValue(arr = []) {
// 先准备max变量放数组的第一个值
let max = arr[0]
// 遍历数组比较
for (let i = 1; i < arr.length; i++) {
if (max < arr[i])
max = arr[i]
}
return max
}
let max = getArrValue([1, 3, 5, 7, 9])
console.log(max) // 9
</script>
返回多个数据
求任意数组中既要最大值还要最小值的使用使用 return[max,min]
<script>
// 求r任意数组的最大值和最小值并返回
function getArrValue(arr = []) {
let max = arr[0] // 给个变量装数组第一个值
let min = arr[0] // 再给个变量装数组第一个值
// 遍历数组比较
for (let i = 1; i < arr.length; i++) {
// 最大值比较
if (max < arr[i]) {
max = arr[i]
}
// 最小值比较
if (min > arr[i]) {
min = arr[i]
}
}
return [max, min]
}
let newArr = getArrValue([1, 3, 5, 7, 9])
console.log(`数组的最大值:${newArr[0]}`) // 9
console.log(`数组的最小值:${newArr[1]}`) // 1
</script>
函数断点调试
断点调试:进入函数内部看执行过程 F11
函数补充
两个相同的函数后面的会覆盖前面的函数。
实参的个数和形参的个数可以不一致时,如果形参过多 会自动填上
undefined
(未知),如果实参过多,那么多余的实参会被忽略(函数内部有一个arguments
,里面装着所有的实参)函数一旦碰到
return
就不会在往下执行了 函数的结束用return
。
<script>
function fn(a, b) {
console.log(a + b) // 1 + 2
}
// 如果实参多于形参,则多于就不参与运算
fn(1,2,3) // 3
// 如果形参多于实参,则多出的形参为未知,数字和undefined参与运算,结果是NaN
fn(1) // NaN
</script>
函数中断程序
// 一个封装函数
function asda() {
if (true) {
console.log(11)
return false // 中断程序,函数里下面的就都不再执行了
}
console.log(12) // 不执行
console.log(13) // 不执行
}
asda() // 调用函数
作用域
一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域:
作用于所有代码执行的环境(整个
<script>
内部)或者一个独立的 js文件
局部作用域:
作用于函数内的代码环境,就是局部作用域。因为跟函数有关系,所以也称为函数作用域。
全局变量:
函数外部
let 变量
,全局变量在任何区域都可以访问和修改。
局部变量
函数内部
let = 变量
,局部变量只能在当前函数内部访问和修改。
<script>
// 全局变量
let num = 10
console.log(num) // 10
function fn() {
console.log(num) //10 全局变量是通用的
}
fn()
// 局部变量
function fun() {
let str = '霍欣标' // 在函数内部声明了一个变量
}
fun() // 结果错误,变量未声明
</script>
函数变量的特殊情况
如果函数内部,变量没有声明,直接赋值,也当全局变量看,但是强烈不推荐
<script>
function fn() {
num = 10 // 局部变量并没有声明,外部也能使用这个变量
}
fn()
console.log(num) //结果是:10
</script>
函数内部的形参可以看做是局部变量
<script>
function fn(x, y) {
// 形参可以看做是局部变量,可以在内部打印
console.log(x) // 1
}
fn(1,2)
console.log(x) // 外部打印不了,结果是错误的
</script>
变量的访问原则
只要是代码,就至少有一个作用域
写在函数内部的局部作用域
如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
访问原则:在能够访问到的情况下先局部,局部没有在找全局
<script>
let num = 10
// 这是个函数
function fu() {
let num = 20
let arr = 100
console.log(num) // 结果是:20
// 里面再写一个函数
function fun() {
let num = 30
console.log(num) //结果是: 30
console.log(arr) //结果是:100
}
fun()
}
fu()
</script>
匿名函数
没有名字的函数,无法直接使用。使用方式有“函数表达式”和“立即执行函数”两种。
函数表达式
将匿名函数赋值给一个变量,并且通过变量名称进行调用 我们将这个称为函数表达式。
<script>
//函数表达式和
// 具名表达式可以写在任何位置,而函数表达式只能写在函数的后面
let fn = function () {
console.log('我是函数表达式')
}
fn()
// 具名函数
fun()
function fun() {
console.log('我是具名表达式')
}
</script>
立即执行函数
场景为了避免全局变量之间的污染。
第一种写法:先写()();
,第一个括号写function(){}
,执行代码写在{}
中,第二个()
可以写实参。
写多个立即执行函数,后面必须写上;
不然会报错
<script>
(function () {
console.log(13)
})();
(function () {
console.log(11)
})();
// (本身还是函数(行参){}) (实参);
(function (x, y) { console.log(x + y) })(1, 2);
</script>
第二种写法:先写一个();
,在这个括号里写function(){}()
<script>
(function (x, y) {
console.log(x + y)
}(1, 2));
// (本身函数(形参) {执行代码} (实参));
(function (x, y) { console.log(x + y) }(1, 2));
</script>
案例:总秒数转换为时分秒
需求:用户输入秒数,可以自动转换为时分秒。
分析:
① 用户输入总秒数(注意默认值)
② 计算时分秒(封装函数) 里面包含数字补0
③ 打印输出
计算公式:
小时:
h = parselnt(总秒数 / 60 / 60 % 24)
分钟:m = parselnt(总秒数 / 60 % 60)
秒数:s = parselnt(总秒数 % 60)
<script>
// 1. 用户输入秒数
let second = +prompt('请输入秒数:')
// 封装函数
function getTime(t) {
console.log(t) // 总秒数
// 2. 转换时间
let h = parseInt(t / 60 / 60 % 24)
let m = parseInt(t / 60 % 60)
let s = parseInt(t % 60)
console.log(h, m, s)
// 3.数字补零
h = h < 10 ? '0' + h : h
m = m < 10 ? '0' + m : m
s = s < 10 ? '0' + s : s
return `转换完毕之后的时间是:${h}时 ${m}分 ${s}秒`
}
let str = getTime(second)
document.write(str)
</script>
逻辑中断
短路:只存在于&&
和||
中,当满足一定条件会让右边代码不执行。
原因:通过左边能得到整个式子的结果,因此没必要再判断右边。
运算结果:无论&&
还是||
,运算结果都是最后被执行的表达式值,一般用在变量赋值
符号 | 短路条件 |
&& | 左边为false就短路 |
|| | 左边为true就短路 |
下面例子,fn
函数实参没有值,则形参中的(x,y)
都是undefined
为假的,false || 0
返回的是后面的值,所以x = 0
<script>
// 实参没有数据,也可以使用逻辑中断给形参赋值
function fn(x, y) {
x = x || 0 // 假的 || 0, x = 0
y = y || 2 // 假的 || 0, y = 0
console.log(x + y)
}
fn() //结果是 0
</script>
&&
先看左边,如果是假的,右边就不再执行了。
// 逻辑运算符一假则假,先看&&左边的,如果错误的,右边就不再执行了
console.log(false && 22) // false
console.log(false && 3 + 5) // false
// 了解拓展
console.log(true && 3 + 5) // 结果是8
console.log(4 && 3 + 5) // 结果是8
console.log('x' && 3 + 5) // 结果是8
||
先看左边,如果是真的,右边就不再执行了。
// 逻辑运算符一真则真,先看||左边的,如果真的,右边就不再执行了
let age = 18
console.log(true || age++); // true
console.log(11 || age++); // 11
console.log(age) // 18
console.log(true || 3 + 5) // true
// 了解拓展
console.log(false || 3 + 5) // 8
console.log(12 || 3 + 5) // 12
console.log('x' || 3 + 5) // x
如果两边都为真,&&
是后面的真值;||
是前面的真值。
<script>
console.log(11 && 22) // 22
console.log(11 || 22) // 11
</script>
转换为Boolean型
''
0
undefined
null
false
NaN
转换为布尔值后都是false
,其余则为true
<script>
console.log(Boolean('xinbiao')) // true
console.log(Boolean('')) // false
console.log(Boolean(0)) // false
console.log(Boolean(90)) // true
console.log(Boolean(-1)) // true
console.log(Boolean(undefined)) // false
console.log(Boolean(null)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean(false)) // false
</script>
<script>
console.log('2' - 2) // 0
console.log(null + 3) // 3
console.log(undefined + 3) // NaN
console.log(null == undefined) // true
console.log(null === undefined) //false
console.log('' - 1) //-1
console.log('xinbiao' - 1) //NaN
console.log(undefined + 1) // NaN
console.log(NaN +1) // NaN
</script>
原创文章,作者:霍欣标,如若转载,请注明出处:https://www.bigengwu.cn/xue/81.html