闭包
闭包的概念
高程上关于闭包的定义:闭包是指有权访问另一个函数作用域中的变量的函数
简单理解就是:定义在一个函数内部的函数
在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
创建闭包的方式:在一个函数内部创建另一个函数
1 | function f1(){ |
其中f2( )
就是一个闭包能够访问它上一级函数f1()
中的变量n。
闭包关于作用域链的图示:
闭包的用途
1、读取其他函数内部的变量
2、让这些变量的始终保持在内存中,这是一个双刃剑,可以方便的访问内部的变量,即使函数执行完成,其内部变量还保存在内存中可以访问,但是也会带来一系列的问题,外部函数的作用域链和变量对象不能销毁,占用内存。
来看一个典型的例子
1 | var result = new Array(); |
从表面上看,似乎每一个函数都返回10 ,但实际上,每个函数都返回10, 因为每个函数的作用域链中都保存着父级函数的活动对象,他们的引用的都是同一个变量i,当父级函数return result
后,变量i的值变成10 ,每个函数引用保存变量i的同一个变量对象,因为此时i=10,所以引用变量指向的值都变成10。
解决这个问题最方便的一个方法是将闭包函数立即执行,每次引用都变成实际i对应的值。每次循环立即执行后销毁引用变量。
1 | var result = new Array(); |
闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
闭包中的this
匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window
闭包的this对象一般也是指向window。具体使用用要看具体的情况,有没有实例化对象,有没有使用apply() call() 等来改变this对象。
面试中问到关于函数闭包的问题
f(a)(b);
要求返回a+b的结果。
面试的时候面试官写出这样的一个表达式,猛一看这个心想坏了,这是什么表达式,我都没见过,一脸懵逼,一开始以为则是一个立即执行函数,仔细一看不对,这是一个函数执行之后再跟一个()
表示执行,还好面试官提示一下,后面的括号就是表示执行函数,那前面的f(a)
表示执行结果返回的是一个函数。
接下来就是写这个函数:两种思路,一种我自己想的,一种网上的,当然是晚上的比较好
1、使用闭包
1 | function f(x) { |
这种方法明显的好,使用闭包,函数里面封装一个函数。最为关键的点在于,闭包就是能够读取其他函数内部变量的函数,就相当于把第一次执行时传入的参数x定义为了一个变量,因为在闭包函数中有对x的引用,所以在函数f执行完成之后,内存中x变量的值并没有被清空,在第二次执行的时候可以正常访问到x,并返回x+y。
其实这个问题在阮一峰-关于闭包的学习中有这个表达式,当时自己看的时候只注意到闭包的作用域,没有注意到函数执行表达式。
2、我的方法
我的方法就比较笨, 将闭包特有的性质单独拿出来实现。
1 | let temp; |