定义函数的方法有两种,一种是函数声明,一种是函数表达式
//函数声明
function app(){
console.log("app");/app
}
//函数表达式
var app=function(){
console.log("app");//app
}
他们两个不同的地方在于,函数声明会有一个提升(相当于会在执行代码前读取函数声明),而函数表达式不会有
//函数声明
app();//yes
function app(){
alert("yes");
}
//函数表达式
console.log(app);//undefined
app();//app is not a function
var app=function(){
console.log("yes")
}
在函数表达式中,就像变量一样,会被赋予undefined值,而不会有提升,所以调用语句必须在函数表达式之后。
递归
要构成一个简单的递归函数,就是通过名字调用自身构成的
function factorial(num){
if(num<=1){
return 1
}else{
return num*factorial(num-1);
}
}
但是这种方式在factorial函数重命名后将出现错误,为了保证日常的修改和使用,将使用下面这种方式
function factorial(num){
if(num<=1){
return 1;
}else{
return num*argumens.callee(num-1);
}
}
console.log(factorial(5));//120;
var anotherFactorial=factorial;
factorial=null;
console.log(anotherFactorial(5));//120
arguments.callee
指向的是当前正在执行的函数,因此可以用他来实现递归
这个方法时常会被我们用来解决for循环中的i值问题
var list=document.getElementsByTagName("li");
(function question(){
for(var i=0;i<list.length;i++){
(list[i].onclick=function(){alert(arguments.callee.i+1)}).i=i;
}
})();
闭包
闭包:指的是有权访问另一个函数作用域中的变量的函数。一般创建闭包的方法就是在函数内部创建另一个函数。
当某个函数被调用的时候,会创建一个执行环境及相应的作用域链,然后使用arguments和其他命名参数的值来初始化活动对象。但是在作用域中,外部函数的活动对象始终位于第二位,外部的外部属于第三位,一直到全局变量为止。我们的后台中每个执行环境都有一个表示变量的对象,全局中的变量对象始终存在,而我们定义的函数这样的局部环境的变量对象只在执行的过程中存在。执行完毕就会被销毁掉,我们的内存中只会保留我们的全局变量,但是闭包就有所不同。
在另一个函数内部定义的函数会将外部函数的活动对象添加到他的作用域链中,当这个内部函数中包含外部函数的变量作为返回值的时候,外部的环境并不会被销毁掉,不然内部的环境将无法找到目标对象,因此匿名函数的作用域链仍然在引用这个活动对象,也就是说,他的执行环境的作用域链会被销毁,但是活动对象仍然会被保留在内存中,知道匿名函数被销毁后,他才会被销毁。
作用域链的这种配置方式引出了一个值得注意的副作用,就是闭包只能取得包含函数中任何变量的最后一个值。
var list=document.getElementsByTagName("li");//设置了1个ul,里面有3个li
(function alertItem(){
for(var i=0;i<list.length;i++){
list[i].onclick=function(){
alert(i);//每次弹出的都是最后的i值
}
}
})();
//解决方法,利用闭包,在函数内部编写函数
(function alertItem(){
for(var i=0;i<list.length;i++){
list[i].onclick=function(num){
return function(){
alert(num+1)
}
}(i);
}
})();
//利用匿名函数
(function alertItem(){
for(var i=0;i<list.length;i++){
(function(argument){
list[i].onclick=function(){
alert(argument+1);//+1只是为了和项目对齐,数组从0开始
}
})(i)
}
})();
//利用对象的键对值
(function alertItem(){
for(var i=0;i<list.length;i++){
list[i].index=i;
list[i].onclick=function(){
alert(this.index+1)
}
}
})();
//利用ES6中的Let
(function alertItem(){
for(var i=0;i<list.length;i++){
let j=i;
list[i].onclick=function(){
alert(j+1)
}
}
})();
//利用arguments.callee
(function alertItem(){
for(var i=0;i<list.length;i++){
(list[i].onclick=function(){alert(arguments.callee.i)}).i=i;
}
})();