闭包
闭包就是可以让函数访问外部变量的函数,其本质就是一个函数,mdn说“函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函数在每次创建时生成闭包。”
用mdn上面的例子来讲
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
let myFunc = makeFunc();
myFunc();
最后运行发现两个都打出了aaa,也就是说闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域,而且内部函数 displayName() 在执行前,就已经被外部函数返回。原因是:
JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用,而 displayName 实例仍可访问其作用域中的变量,即可以访问到 name 。由此,当 myFunc 被调用时,name 仍可被访问,其值 Mozilla 就被传递到alert中。
注意!!!!
作用域会被保留
通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。
eg
function Add(x) {
return function(y) {
return x + y;
};
}
let add5 = Add(5);
let add10 = Add(10);
console.log(Add5(2)); // 7
console.log(Add10(2)); // 12
let add5=null
let add10=null//此时才可以被销毁
从上述代码可以看到add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。这时候可以发现里面的那个关于y的函数和其作用域有被保留,直到最后通过 null才 释放了 add5 和 add10 对闭包的引用。
在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;
如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
闭包只能取得包含函数中的任何变量的最后一个值
eg.
function Arr(){
let arr=[]
for(i=0;i<10;i++){
arr[i]=function(){
return i}
}
return arr
}
这里,我们发现
没return i
也就是说用闭包时候,只能return最后最外面那个值,当Arr执行完毕后,其作用域被销毁,但它的变量对象仍保存在内存中,得以被匿名访问,这时i的值为10。
要想保存在循环过程中每一个i的值,需要在匿名函数外部再套用一个匿名函数,在这个匿名函数中定义另一个变量并且立即执行来保存i的值。
function Arr(){
let arr=[]
for(i=0;i<10;i++){
arr[i]=function(num){
return function(){
return num
}
}(i)
}
return arr
}
这时最内部的匿名函数访问的是num的值,所以数组中10个匿名函数的返回值就是1-10
闭包中的this对象
要注意this指向的是函数作用时候的环境,和函数名的环境要分开看。eg
var name=`window`
var obj={
name:`obj`,
getName:()=>{
return ()=>{
return this.name
}
}
}
console.log(obj.getName()())
在上面这段代码中,obj.getName()()实际上是在全局作用域中调用了匿名函数,this指向了window。
结果是window而不是obj
作用
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
而且其最最最直观的作用,就是我们可以通过这个方法,把我们的操作封装起来,只留一些外部接口,这样即可以使得后面的代码看起来很简洁,又可以不让别人改动到我们的核心代码。这个被称为‘方法的私有化’。
缺点
闭包的缺点:
比普通函数占用更多的内存。
解决:闭包不在使用时,要及时释放。
将引用内层函数对象的变量赋值为null。
网友评论