一、匿名函数
- 又叫立即执行函数,因为是匿名所以不能被调用,因为不能被调用所以不立即执行就没有意义,因为立即执行所以执行完后就会被销毁
- 匿名函数就是函数的直接量
- IIFE和回调函数适合使用匿名函数
(function(num) {
console.log('匿名函数',
num);
})(101);
二、立即调用的函数(IIFE)
- 函数声明完立即调用就是IIFE,通常使用匿名函数
- 立即调用的函数主要为了产生作用域,避免全局变量污染
// 匿名的函数立即调用
(function(){
console.log('我是立即调用的函数!');
})();
// 匿名的有参数的函数立即调用
(function(a,b){
console.log(a + b);
})(100,200*232+323/324);
// 有名字的函数立即调用(无意义)
(function fn() {
console.log('我是fn');
})();
两个连续的自调用函数,之间必须加分号,告诉浏览器是不同的函数,否则会有语法错误。或者,在后面的自调用函数前加 ! 等没有副作用的一元运算符
三、回调函数
1. 概念
满足以下三个条件的函数就是回调函数:
- 函数是我定义的
- 我没有调用函数
- 函数执行了
2. 使用场景
- 定时器的回调函数
- DOM 事件的回调函数
- Ajax 的回调函数
- Promise 的回调函数
- 需要回调函数作为参数的方法,如数组的方法:forEach()、filter()、map() 等
回调函数大部分都是作为其他函数或方法的参数!
3. 实现
- 声明一个函数 fn,函数的参数类型要求是函数。
- fn 的函数体内,调用传递进来的回调函数。
- fn 内部调用回调函数的时候,还可以给回调函数传个实参
// 定义函数,需要一个回调函数当参数
function func(cb) {
cb();
}
// 调用func 设置一个回调函数当实参
func(function(){
console.log('hello,我是回调函数!');
});
4. 作用域
看上层作用域是谁,和在哪里调用无关和cb()调用无关,只和在哪里定义有关
var num = 200;
function func(cb) {
var num = 100;
cb();
}
function fn() {
console.log(num); // 200
}
func(fn);
四、递归函数
1. 概念
一个函数的内部如果又调用了自己,称为函数的递归调用,存在递归调用的函数就是递归函数。
// 定义函数,计算某个数字的阶乘 结果返回
function fn(n) {
if (n <= 2) {
return n;
}
return n * fn(n-1)
}
console.log('4的阶乘', fn(4));
/*
fn(4) 开始调用 4*fn(3)
fn(3) 开始调用 3*fn(2)
fn(2) 开始调用
fn(2) 结束调用 return 2
fn(3) 结束调用 return 6
fn(4) 结束调用 return 24
*/
2. 成功的条件
- 有明确的结束递归的条件(最终停止递归调用)
- 随着递归调用次数增加,越来越趋向于结束递归
3. 缺点
理解难度大,运行效率低
//斐波那契数列
function fib(n) {
if (n < 2) return 1;
return fib(n - 1) + fib(n - 2)
}
var arr = [];
for (var i = 0; i < 10; i++) {
arr.push(fib(i))
}
console.log(arr); //[1,1,2,3,5,8,13,21,34,55]
//递归数组拉平
var nums = [[1000, 2000, 3000], "hello", [[10, 20, 30], ["a", "b", ["A", "B", "C"]], "nikki"], 12313, [101, 202, 303]];
function arrayFlat(arr) {
let newNums = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] instanceof Array) {
newNums = newNums.concat(arrayFlat(arr[i]));
} else {
newNums.push(arr[i]);
}
}
return newNums;
}
console.log(arrayFlat(nums));