首先函数的定义
方式两种:
1、函数声明
2、函数表达式
注意:
当函数声明时,它会函数声明提升,这样的话,我们就可以把函数声明放在调用它的后面。请看:say() function say(){ alert('hi'); }
如果在函数表达式中这样调用就会报错。为啥?,因为它相当于这样写:
let say; say(); say = function(){ alert('hi'); } //你敢说这样不报错?鬼信。
但是函数表达式也有它的好处的,请看下面两个写法:
例子1: if(condition){ function say(){ alert('hi'); } }else{ function say(){ alert('hid'); } } 例子2: let say; if(condition){ say = function(){ alert('hi'); } }else{ say = function(){ alert('hid'); } }
例子1的写法不是不可以,但是,现实很残酷,有些浏览器在尝试修正错误的做法不一致,大多数浏览器会返回第二个声明,忽略condition,这就很不好啦。
例子2就可以解决这个问题,它会根据condition来赋值,而不像替换那样做。
递归
废话不多说,直接上例子:
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1);
//return num * factorial(num -1);
}
}
问题来啦~为啥我们不写成注释的那样,那样不是才能更加符合我们的思维吗?
答:因为有种情况会出错,那就是当参数是函数时,里面的factorial不会跟着参数变化,所以就使用了arguments.callee()来替代函数名,但是,在严格模式下,不能通过脚本访问arguments.callee,访问这个属性会报错,不过呢,可以使用命名函数表达式来达成相同的结果。如:let factorial = (function f(num){ if(num <= 1 ){ return 1; }else{ return num * f(num - 1); } })
模拟块级作用域
首先说一下,见过这种写法没:
(function(){
...
})()
其实这样我们就模拟出了一个作用域来,咋个说,()括号是什么作用,是不是代表一个表达式,还有后面的括号,是不是会让这个函数立即执行。这样我们就可以得到私有作用域啦,不会污染到全局里面去。
这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就会立即销毁其作用域链。