这个问题的经典性,几乎所有面试官都会问到这个问题,什么情况下会发生闭包,为什么需要闭包,什么场景下需要,闭包闭了谁,怎么释放被闭包的变量内存,闭包的优点是什么,缺点是什么等等。
http://www.cnblogs.com/xxcanghai/p/4991870.html
JS中有几种函数
具名函数 (命名函数)和匿名函数。
创建函数的几种方式
1.声明函数
2.创建匿名函数表达式
3.创建具名函数表达式
4.Function构造函数(可以得到想要的结果,类似eval)
var str='2+5+8';
alert(new Function('return '+str)());
返回的结果是15。
5.自执行函数
(function(){alert(1);})();
(function fn1(){alert(1);})();
6.其他创建函数的方法
当然还有其他创建函数或执行函数的方法,这里不再多说,比如采用 eval , setTimeout , setInterval 等非常用方法,这里不做过多介绍,属于非标准方法,这里不做过多展开。
注意:所有声明的匿名函数都是一个新函数;
所有new出来的函数也都是一个新的函数。
函数作用域链:
作用域:就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期,在JavaScript中变量的作用域有全局作用域和局部作用域。
var a=3; //全局变量
function fn(b){ //局部变量
c=2; //全局变量
var d=5; //局部变量
function subFn(){
var e=d; //父函数的局部变量对子函数可见
for(var i=0;i<3;i++){
console.write(i);
}
alert(i);//3, 在for循环内声明,循环外function内仍然可见,没有块作用域
}
}
alert(c); //在function内声明但不带var修饰,仍然是全局变量
预解析
JavaScript虽然是解释执行,但也不是按部就班逐句解释执行的,在真正解释执行之前,JavaScript解释器会预解析代码,将变量、函数声明部分提前解释,这就意味着我们可以在function声明语句之前调用function。
console.log(a); //undefined
var a=3;
console.log(a); //3
console.log(b); //Uncaught ReferenceError: b is not defined
执行环境
定义了变量或函数有权访问的其它数据,决定了它们的各自行为。
全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,因此所有全局变量和函数都是作为window对象的属性和放大创建的。每个函数都有自己的执行环境,当执行流进入一个函数的时候,函数的环境会被推入一个函数栈中,而在函数执行完毕后执行环境出栈并被销毁,保存在其中的所有变量和函数定义随之销毁,控制权返回到之前的执行环境中,全局的执行环境在应用程序退出(浏览器关闭)才会被销毁。
作用域链:JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
在函数运行过程中标识符的解析是沿着作用域链一级一级搜索的过程,从第一个对象开始,逐级向后回溯,直到找到同名标识符为止,找到后不再继续遍历,找不到就报错。
闭包:广义上的闭包就是指一个变量在他自身作用域外被使用了,就叫发生了闭包。(父级函数的局部变量对子级可见,可以被子级调用)
经典问题,一目了然:
for(var i=0;i<elements.length;i++){
elements[i].onclick=function(){
alert(i);
}
}
闭包不能滥用:
闭包会使子函数保持其作用域链的所有变量及函数与内存中,内存消耗很大,在使用的时候尽量销毁父函数不再使用的变量。