没想到函数也要单独开一章。
1 基本特点
js中函数是一等公民,是很特殊的存在。
function fn(){}
typeof fn // 'function'
fn instanceof Object //true
fn instanceof Function // true
箭头函数arrow funciton、函数递归、闭包。
箭头函数中没有 arguments/this/prototype new.target
的概念,简化了不少,自然也就不能 new
在js中不在乎参数个数,但可以通过 ...args
获得参数,并针对性做出判断,判断类型和个数,来模拟实现重载。
function 会函数声明提升 function declaration hoisting
函数可以作为值进行传递。
函数内部存在 arguments/this/new.target 用来表示 函数是否通过new调用,值为被调用构造函数。
函数存在prototype JS基础之继承、原型链、面向对象
函数还有两个方法 apply/call/bind ,可以改变this的指向 JS之this和改变this
2 递归
默认递归。
尾调用优化、尾调用 Tail Call Optimization
书籍《学习Javascript数据结构与算法》 第九部分,递归
理解递归、基本应用、js调用栈
2.1 概念
直接或者间接调用自身的函数,是递归函数。
比如求 5!=5*4*3*2*1
的结果
很容易用一层for循环写出来,基本上没有难度:
function fun(number=1) {
if(n<0) return undefined
let total = 1
for(let i=number;i>1;i--){
total = total * n
}
return total
}
接下来我们分解,分解为 n * (n-1),达到类似的结果:
function fun(n){
if(n===1||n===0){
return 1
}
return n * fun(n-1)
}
这就是最基础的递归了。先膨胀到最大,然后逐一解决缩短调用链路。
也就是使用了栈的概念
提到栈,一定考虑爆栈,也就是超出栈的最大长度,也叫溢出。 StackOverflowError
2.2 尾调用
因此在es6之后有了 尾调用优化Tail Call Optimization : 如果函数最后一个操作是调用函数,走的是 jump,结果是代码可以一直执行下去。https://www.chromestatus.com/feature/5516876633341952
应用场景2 斐波那契数列 0 1 2 3 5 8 后者是前两个相加。
我们使用for循环很容易写出下面的代码
function fun(n){
if(n<1) return 0;
if(n<=2) return 1
let n1=0
let n2=1
let nn =n
for(let i=2;i<=n;i++){
nn = n1 + n2
n2 = n1
n1 = n
}
return nn
}
我们也可以简单改为递归。
funct fun(n){
// if
return fun(n-1)+fun(n-2)
}
顺着这个思路往后看,可以引入缓存,维护了一个数组存放结果。
function fun(n){
const memo = [0,1]
const f = n => {
if(memo[n]!=null) return memo[n]
return memo[n] = f(n-1,memo) + f(n-2,memo)
}
return f
}
??
通过数据表明,迭代比递归。
但递归思路更清楚,有了尾调用优化,递归可以进一步优化。
外部函数的返回值是一个内部函数的返回值
function 外函数(){
return 内函数() // 尾调用
}
es6优化之前:
- 开始执行外函数,推栈。
- 执行到 return,要 return 就得先计算内部函数
- 那就执行内函数,推栈
- 执行完内函数,给 return
- return 拿到就丢出来
- 弹栈
es6优化之后:
- 开始执行外函数,推栈。
- 执行到 return,要 return 就得先计算内部函数
- 引擎发现把外函数弹出栈外也没问题,因为内函数的函数值会被return ,也就是外函数的return,那就弹了吧,现在栈空了
- 执行内函数,内函数推栈
- 执行,并返回
- 弹栈
优化了之后,无论内函数怎么折腾,外函数不参与。关键就是确定外函数真的没必要存在了。
什么情况下会启用尾调用优化:
- 外部函数返回值是对未调用函数的调用
- 函数返回后不需要额外逻辑
- 不是闭包
- 严格模式
闭包
https://www.yuque.com/xinbao37/roadmap/js-scope-and-closure
私有方法
需要review