闭包一词在javascript中很是有名,对于前端来讲理解它相当重要,不少高级应用都要依靠闭包实现。掌握了它,对咱们的js写代码水平会有很大帮助,所以成为许多公司前端的面试题之一,用来测试应聘者的js水平,可见其重要性,因此做为一个前端,理解闭包是必须的!没有任何理由说不懂!javascript
理解闭包,首先必须理解变量做用域和做用域链。在JavaScript中,JavaScript有两种做用域:全局做用域和函数做用域。函数内部能够直接读取全局变量。函数子做用域能够访问父做用域的变量 。前端
var n = 1;
function f1() {
console.log(n);
}
f1() // 1
复制代码
上面代码中,函数f1能够直接访问全局变量n, 可是在函数外部没法直接读取函数内部的变量,java
function f1() {
var n = 1;
}
console.log(n)
//Uncaught ReferenceError: n is not defined 提示n没有定义
复制代码
若是出于种种缘由,须要获得函数内的局部变量。正常状况下,这是办不到的,只有经过变通方法才能实现。那就是在函数的内部,再定义一个函数。面试
function f1() {
var n = 1;
function f2() {
  console.log(n); // 1
}
}
复制代码
上面代码中,函数f2就在函数f1内部,这时f1内部的全部局部变量,对f2都是可见的。可是反过来就不行,f2内部的局部变量,对f1就是不可见的。子对象会顺着做用域链找父对象的变量, 若是想要函数外部访问函数内部的变量,那么可使用return把f2做为返回值,不就能够在发外部访问到内部的变量了吗?浏览器
function f1() {
var n = 1;
function f2() {
  console.log(n); // 1
}
return f2
}
var result = f1();
result(); // 1
复制代码
上面代码中,函数f1的返回值就是函数f2,因为f2能够读取f1的内部变量,因此就能够在外部得到f1的内部变量了。 f2就是闭包,。闭包是指有权访问另外一个函数做用域中的变量的函数。在这里要注意的一点:因为一般闭包都是匿名函数,因此给人形成错觉,只有匿名函数才能做为闭包,其实,命名、匿名函数都是能够做为闭包函数的,只不过一般闭包都是做为返回值,自身不多被调用,因此也就没了命名的必要,而命名函数基本上都是要调用的。bash
另外看了网上一些文章,是经过做用域的提高来解释的, f1是一级做用域,f2是二级做用域,f1返回f2后,把f2的做用域提高到一级做用域,就能够在外部被全局调用了,这种说法通俗易懂,很好理解,可是闭包
1.函数内部的定义的变量能够保存在内存中。通常函数运行后,函数内部的变量就会被销毁,可是因为闭包的存在,该函数内部的变量就不会被销毁回收,如上述代码中,f1调用后,闭包f2会调用变量n,使得n始终存在内存中。 2.避免全局变量的污染,全局变量是可重用可是污染全局,局部变量不会污染全局可是不可重用。而闭包就是两者优势的结合, 3.是封装对象的私有属性和私有方法。举例以下:函数
function Person(name) {
var _age;
function setAge(n) {
_age = n;
}
function getAge() {
return _age;
}
return {
name: name,
getAge: getAge,
setAge: setAge
};
}
var p1 = Person('张三');
p1.setAge(25);
p1.getAge() // 25
该例子来源与阮一峰的博客函数闭包内容,
复制代码
上面代码中,函数Person的内部变量_age,经过闭包getAge和setAge,变成了返回对象p1的私有变量。性能
闭包会保留外层函数的内部变量,因此内存消耗很大。所以不能滥用闭包,不然会形成网页的性能问题。测试
备注:以前闭包在iE浏览器上存在内存溢出的问题,不过这是因为ie的垃圾回收机制引发的,目前已经修复这个问题,