参考链接:https://www.cnblogs.com/echolun/p/11897004.html
1、什么是闭包?
闭包在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。
我个人的理解更多是 :A函数里面嵌套了一个B函数,B函数使用了A函数的内部变量,且A函数返回B函数,这就是闭包。还有一种概念就是:所谓闭包其实就是一个自带了执行环境(由外层函数提供,即便外层函数销毁依旧可以访问)的特殊函数;那么回到文章开头的提问,这段代码中的闭包指代的就是内部函数 insider,而非外部函数outer所包含的范围,这一点一定得弄清楚。
2、闭包产生的条件
1.函数嵌套
2.内部函数引用了外部函数的数据(变量/函数)
3.执行外部函数
3、闭包的特征
1. 首先他是一个函数。
2.闭包能访问外部函数作用域中的自由变量,即使外部函数上下文已销毁。
1 function fn1() {
2 //此时闭包就已经产生了(函数提升, 内部函数对象已经创建了)
3 var a = 2
4 function fn2 () {
5 a++
6 console.log(a)
7 }
8 // var fn2 = function () { //若是这样写要等这行执行完闭包才产生,函数定义执行
9 //
10 // }
11 return fn2
12 }
13 //fn1() //若是这样执行,第一次执行完成以后闭包就不再存在
14 var f = fn1()
15 f() // 3
16 f() // 4
17 f = null //不再引用,闭包死亡(包含闭包的函数对象成为垃圾对象)
这是一个典型的闭包,fn2嵌套在fn1里面,fn2引用了fn1的局部变量a,fn1返回了fn2,执行了fn1函数,当执行完 var f = fn1(),fn1会从执行上下文中弹出并销毁。
那么为什么函数都销毁了,为啥还能访问到它里面的变量,我个人的理解应该是引用和作用域链的关系,需要查资料核实。
当我们不再使用的时候就让它等于null,进行释放,以免造成内存泄漏。
4.闭包的作用
创建私有属性和方法
构造函数:
function Person(name) {
//这是一个私有属性
var age = 3;
//这些是构造器属性
this.name = name;
this.hello = function () {
console.log(`我的名字是${this.name},我今年${age}岁了`);
};
};
var person = new Person('leah');
person.hello();//我的名字是leah,我今年3岁了
如果某个属性方法在所有实例中都需要使用,我们一般推荐加在构造函数的prototype原型链上,还有种做法就是利用私有属性。比如这个例子中所有实例都可以正常使用变量 age。同时我们将age称为私有属性的同时,我们也会将this.hello称为特权方法,因为你只有通过这个方法才能访问被保护的私有属性age啊。
函数工厂:
function makeAdder(x) {
return function (y) {
console.log(x + y);
};
};
var a = makeAdder(5);
var b = makeAdder(10);
a(2); // 7
b(2); // 12
在这个例子中,我们利用了闭包自带执行环境的特性(即使外层作用域已销毁),仅仅使用一个形参完成了两个形参求和的骚操作,是不是很奈斯。当然例子函数还有个更专业的名词,叫函数柯里化。