函数名是指针,函数是对象
函数表达式
函数声明:函数声明提升,代码之前会先读取函数声明
1).以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的.
2).以函数声明的方法定义的函数,函数可以在函数声明之前调用,而函数表达式的函数只能在声明之后调用.
3).以函数声明的方法定义的函数并不是真正的声明,它们仅仅可以出现在全局中,或者嵌套在其他的函数中,但是它们不能出现在循环,条件或者try/catch/finally中,而函数表达式可以在任何地方声明.
递归
arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}
这个函数的执行与函数名 factorial 紧紧耦合在了一起。为 了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee
在这个重写后的 factorial()函数的函数体内,没有再引用函数名 factorial。这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用。
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
var trueFactorial = factorial;
alert(trueFactorial(5)); //120
factorial = function() {
return 0;
}
alert(trueFactorial(5));// 120 如果没有使用arguments.callee,将返回0
访问 arguments 是个很昂贵的操作,因为它是个很大的对象,每次递归调用时都需要重新创建。影响现代浏览器的性能,还会影响闭包。
现在arguments.callee 被弃用了。怎么办,其实很简单,给内部函数一个名字即可(当函数被调用时,它的arguments.callee对象就会指向自身,也就是一个对自己的引用。)
闭包
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
有权访问另一个函数作用域内变量的函数都是闭包。
闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!
作用域链的机制导致了一个问题,在循环里的匿名函数取得的任何变量都是最后一个值
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i]=function(){
return i;
}
}
//循环已经执行完毕了,i最终为4++即5
return arr;
}
var b=box();
for(var i=0;i<b.length;i++){
alert(bi);
}
//5 5 5 5 5
//解决方法,单纯得到0 1 2 3 4 ---->无需使用匿名函数
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i]=i;
}
return arr;
}
for(var i=0;i<5;i++){
alert(box()[i]);
}
//通过匿名函数及时自我执行
function box() {
var arr = [];
for(var i = 0; i < 5; i++) {
arr[i] = (function(num) {
return num;
})(i);
}
return arr;
}
var b = box();
for(var i = 0; i < b.length; i++) {
alert(b[i]);
}
//通过闭包可以将变量驻留内存中
function box() {
var arr = [];
for(var i = 0; i < 5; i++) {
arr[i] = (function(num) {
return function(){
return num;
};
})(i);
}
return arr;
}
var b = box();
for(var i = 0; i < b.length; i++) {
alert(b[i]);
}