高阶函数
高阶函数
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
const personArr = [
new Person("张三", 49),
new Person("李四", 50),
new Person("杰克", 17),
new Person("汤姆", 5),
]
function filter(arr, cb) {
const arrNew = []
for(let i=0; i<arr.length; i++) {
if( cb(arr[i]) ) {
arrNew.push(arr[i])
}
}
return arrNew
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = filter(personArr, a => a.name === "张三" )
result = filter(personArr, a => a.age === 17 )
result = filter(arr, a => a%2 === 0 )
console.log(result)
像
filtr
这种函数我们称为高阶函数, 即 一个函数的返回值或者参数是一个函数
- 将函数作为参数, 称为回调函数, 意味着可以对一个函数动态的传递代码
function someFn() { //1.定义一个 someFn 函数
return "hello"
}
function outer(cb) { //2.定义 outer 函数, 并声明形参cb, 且接受实参--> someFn 函数
//返回值作为参数
return () => {
console.log('记录日志--')
const result = cb() //5.将 someFn 函数的返回值, 赋值给result
return result //6.将 someFn 函数的返回值作为 outer 函数的返回值, 返回
}
}
let result = outer(someFn) //3.传入实参 someFn函数
console.log(result()) // -->4.调用outer函数
function test() { //1.定义一个 test 函数
console.log('test--')
return "test"
}
let r = outer(test) //3.传入实参 test 函数
console.log(r()) //4. 调用 outer
在不修改原函数的基础功能上, 使可以增加其功能
通过高阶函数来动态生成一个新的函数
闭包
闭包的简介
function fn() {
let num = 0
//闭包
return () => {
num ++
console.log(num)
}
}
let result = fn()
console.log(result())
闭包:
闭包就是能访问到, 外部函数作用域中变量的函数, 在我们需要隐藏一些不希望被别人访问到的内容时可以使用闭包
闭包的构成:
- 函数的嵌套
- 内部函数要引用外部函数中的变量
- 内部函数要作为返回值返回
闭包的原理
let a = '全局变量a'
function fn() {
console.log(a)
}
function fn2() {
let a = 'fn2中的a'
// console.log(a)
fn()
}
fn2() // 全局变量a
function fn3() {
let a = 'fn3中的a'
function fn4() {
console.log(a)
}
fn4()
}
fn3() //fn3中的a
function fn5() {
let a = 'fn5中的a'
function fn6() {
console.log(a)
}
//闭包
return fn6
}
let result = fn5()
console.log(result()) //fn5中的a
函数作用域, 在函数创建的时候就已经被确定(词法作用域)
闭包就是利用词法作用域
闭包的一些注意事项
function outer() {
let someVariable = "someValue"
//闭包
return function() {
console.log(someVariable)
}
}
function outer2() {
let num = 0
return () => {
num ++
console.log(num)
}
}
let fn = outer2()
let fn2 = outer2()
//闭包被创建
fn()
fn2()
//释放指针, 闭包销毁
// fn = null
// fn2 = null
闭包的生命周期:
- 闭包在外部函数调用时产生, 外部函数每次调用都会产生一个全新的闭包
- 在内部函数丢失时销毁, (内部函数被垃圾回收了, 闭包才会消失)
闭包的注意事项:
- 闭包主要用来隐藏一些不希望被外部访问到的内容, 这意味着闭包需要占用一定的空间,
- 相比较类来说, 闭包比较浪费内存空间(类可以使用原型,而原型不会重复创建, 但是闭包不能)
- 需要执行次数少时,使用闭包(推荐使用闭包,因为类存在
this
指向的问题)- 需要大量创建实例时,使用类
递归
//求任意一个数的阶乘
//方式一: 循环方式
function jieCheng(num) {
let result = 1
for(let i=2; i<=num; i++) {
result *= i
}
return result
}
let result = jieCheng(3);
console.log(result);
//方式二: 递归方式 -- 尽量打断点分步执行, 理解递归函数的执行机制
function jieCheng2(num) {
//基线条件 -- num等于1时结束函数, 返回1
if(num === 1) {
return 1
}
//递归条件
return jieCheng2(num-1) * num
}
console.log(jieCheng2(5))
递归:
- 调用自身的函数称为递归函数
- 递归的作用和循环基本一致
核心思想:把一个大的问题拆分成一个一个的小问题进行解决
注意: 递归比循环更耗费性能, (递归每次调用函数都会创建函数作用域,占用内存空间)
递归练习
//求斐波那契数列(从1开始, 当前数等于前两个数之和)的第n个数
//递归
function fib(num) {
if(num <= 0) {
return -1;
}
//基线条件
if(num < 3) {
return 1
}
//递归条件
return fib(num-1) + fib(num-2)
}
console.log(fib(6))
//循环
function Fibo(n) {
if(n <= 0) {
return -1;
}
if(n <= 2) {
return 1;
}
let pre = 1; //第一次循环pre是f(1)也就是1
let next = 1; //第一次循环next是f(2)也就是1
let n_value = 0; // 保存f(n)的值
for(let i = 3; i <= n; i++) {
n_value = pre + next; //每一次循环n_value就是前两个数的和
pre = next; // 然后把next赋值给pre
next = n_value; //把新的n_value的值赋值给next
}
return n_value;
}
console.log(Fibo(12))