一.什么是回调函数?
简单说就是,你想在某个特定的时间点执行某些操作。
例如:张三跟女朋友吃完饭,对女朋友说到家记得发短信告诉我,女朋友然后回到家之后,给张三说:我到了,请放心。这个发短信这个事是提前说好的,这个动作就是回调函数。
模拟如上实例代码:
function girl(boyname){
alert(boyname+'我回到家了')
}
//boy为主函数,girl函数作为参数传到boy中,girl就是我们所说的回调函数
function boy(girl,name){
alert('回到家记得告诉我')
alert('女孩回家路上')
girl(name)
}
boy(girl,"张三")
再例如:平时我们请求数据库的操作,然后返回的查询结果也是使用的回调函数。
模拟请求数据库操作:
// 在调用函数A时, 他的参数是另一个函数B, 此时函数B就是函数A的回调函数
setTimeout1(function(err, data){
console.log("执行了setTimeout1的回调函数")
if(err){
console.log(err.message)
}else{
console.log(data)
}
})
// 以下是 setTimeout1 函数的内部实现原理
function setTimeout1(callback){
// 形参callback表示一个函数, 这个函数在调用setTimeout1时传入, 叫做回调函数
// callback()
// 使用随机数模拟, 数据库查询操作, 随机数<0.5说明查询失败 >=0.5说明查询成功
if(Math.random()<0.5){
callback({message:"查询失败,原因不详"}, null)
}else{
callback(null, "查询结果数据")
}
}
二.什么是递归函数?
简单说,递归就是一次次的调用自身,当满足某个条件时,递归结束。
实例如:目录结构的展开和斐波那契数列
// ------------------ (一)什么是递归? -----------------
// 普通的函数
function method1(){
console.log("普通函数")
}
// 函数不会主动执行,需要被动调用才会执行, 而且必须在函数外部调用
method1()
// 递归函数 : 在函数内部调用这个函数自身, 形成一个调用循环
function method2(){
console.log("递归函数")
// 如果一个函数的调用出现在这个函数内部, 那这个函数就叫递归函数
// method2()
}
// 递归函数也必须在函数外部调用一次, 以进入递归循环
method2()
// --------------------- (二)递归如何使用? --------------
// 向上边的写法, 递归函数很容易进入死循环
// 一般递归函数有两种解决方案, 防止递归进入死循环报错
// 1, 在函数内部调用函数自身时,不直接调用,而是用计时器调用, 可以防止报错
function method3(){
console.log("递归函数")
setTimeout(method3, 100)
// requestAnimationFrame(method3)
}
method3()
// 2, 递归函数一般需要添加判断条件, 在不满足条件是,结束递归,防止死循环
var count = 0;
function method4(){
console.log("递归" + count)
count ++;
if(count < 100){
method4()
}
}
method4()
// ----------------------- (三)什么情况下使用递归? -------------
// 1, 在使用requestAnimationFrame实现页面动画时, 要用递归调用
// 2, 在处理多层嵌套数据时, 可能需要用到递归
var array = [
"一级标题A",
"一级标题B",
[
"二级标题C",
["三级标题D", "三级标题E"],
["三级标题F", "三级标题G", '三级标题H', ["四级标题I"]]
]
]
// 假设以上嵌套数组是一个不稳定的结构, 数组层数未知,数组结构有可能动态更新
function method5(arr){
//在解决多层嵌套问题时, 递归函数一般有参数, 而且每次递归的参数都不同
// 对数组遍历
arr.forEach(item=> {
// 判断这个数据是字符串还是数组
if(typeof item == "string"){
document.writeln(item)
}else{
// 既然item不是字符串,那肯定是数组, 接着继续遍历这个数组
method5(item)
}
});
}
method5(array)
// 3, 求斐波那契数列第22位数字
// 0、1、1、2、3、5、8、13、21、34、… 相邻两个数字的和为下一个数字
var count = 1;
function method6(x, y){
count ++;
if(count <= 22){
method6(y, x + y)
}else{
console.log(x)
}
}
method6(0, 1)
总结:如果要在特定时刻执行某些操作,就用回调,即主函数传参时传进一个函数名。
如果要重复操作相同的事情时,请选择递归。