一、函数表达式
定义函数的两种方式:一个是函数声明,另一个就是函数表达式。
//1.函数声明写法
function fn2(){
console.log(‘函数声明’);
}
//2.函数表达式写法
var fn1 = function(){
console.log(‘函数表达式’);
}
区别:
1.函数声明是用function后面有函数名,函数表达式是赋值形式给一个变量。
2.函数声明可以提升函数,而函数表达式不会提升
函数提升就是函数会被自动提升到最前方,以至于再调用函数后再声明函数也不会有错:
//例子:
//先调用运行
sayName();
//再声明函数
function sayName(){
console.log(‘ry’);
}
//运行结果
‘ry’
函数表达式就不会被提升:
//先调用
sayBye();
//函数表达式
var sayBye = function(){
console.log(‘bye bye’);
}
//运行报错
但是下面的写法很危险:因为存在函数声明的提升
//书上代码
if(condition){
function sayHi(){
console.log(‘hi’);
}
}
else{
function sayHi(){
console.log(‘yo’);
}
}
解说一下: 这段代码想表达在condition为true时声明sayHi,不然就另一函数sayHi,但是运行结果往往出乎意料,在当前chrome或firefox可能能做到,但是在IE10以下的浏览器(我测试过)往往不会遵循你的意愿,不管condition是true还是false都会输出yo。
这时函数表达式能派上用场了:
//换成函数表达式,没问题因为不会被提升,只有当执行时才赋值
var sayHi = null;
if(condition){
sayHi = function (){
console.log(‘hi’);
}
}
else{
sayHi = function sayHi(){
console.log(‘yo’);
}
}
(给大家推荐一个前端内部学习群:675498134,进群找管理免费领取学习资料和视频。没有错就是免费领取!大佬小白都欢迎,大家一起学习共同进步!)
二、闭包
闭包的定义:有权访问另一个函数作用域中的变量的函数
有人觉得闭包很难理解,一开始我也是这样的,我认为那是对一些概念还不够了解。
定义中说明了什么是闭包,最常见的形式就是在函数中再声明一个函数。
重点理解这里:
1.闭包能访问外围函数的变量是因为其作用域链中有外围函数的活动对象(这个活动对象即使在外围函数执行完还会存在,不会被销毁,因为被闭包引用着)。
2.闭包是函数中的函数,也就是说其被调用时也创建执行上下文。
理解了上面之后我们再来看闭包的例子:
function a(){
//a函数的变量
var val_a = “我是a函数里的变量”;
//声明函数b,b能访问函数a的变量
function b(){
console.log(val_a);
}
//a函数将b返回
return b;
}
//全局变量fn,a执行返回了b给fn
var fn = a();
//调用fn,能够在全局作用域访问a函数里的变量
fn(); //我是a函数里的变量
这里fn能够访问到a的变量,因为b中引用着a的活动对象,所以即使a函数执行完了,a的活动对象还是不会被销毁的。这也说明过度使用闭包会导致内存泄漏。
1.错误的例子:
屡一下思路,每个li都有click执行的函数,每个函数点击后才会执行是吧,那每个click的函数的外层函数是fn这个函数,那这5个click函数都会保存着fn的活动对象,那这个输出的i变量在fn这函数里面,所以当fn执行完后,i的值是5了,因此当每个里触发click的函数的时候输出的也就是5了。
再简单的说:每个li的click事件触发的函数引用的i在同一个活动对象中,所以值都一样。
2.正确执行的例子:
我们就在外层加了一层匿名函数并立即执行(虽然函数被执行了,如果有函数引用着它的活动对象,那其活动对象将不灭),这时每个li的click函数外层函数是每次循环产生的不同的匿名函数,这匿名也是有活动对象,每个li的click的函数保存着各自的匿名函数的活动对象,num这变量也根据每次循环产生不同的匿名函数传入的i的不同而不同,所以能够输出对应不同的值。
来源: http://geek.csdn.net/news/detail/247389