js闭包学习笔记

时间:2021-10-10 22:41:17

闭包理解:函数中的函数,可以理解为作用域中的作用域

只有理解这几个概念,才能理解闭包:引用,作用域链,值传递

作用域:它是指对某一变量和方法具有访问权限的代码空间, 在JS中, 作用域是在函数中维护的。表示变量或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境。Javascript的作用域只有两种:全局作用域和本地作用域,本地作用域是按照函数来区分的。
闭包:在js中的我的理解就是函数嵌套函数,当内部函数在定义它的作用域的外部被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.

消除闭包2种方法(就是消除变量的引用):1,函数参数是值传递,用以解决闭包变量保留问题。2,在闭包内删除引用的变量。
变量值驻留内存理解:变量只有不被引用了,其占用的内存才会被回收.
为什么会有闭包:因为js的作用域是以函数为划分,所以有函数,就会产生作用域嵌套,被嵌套的作用域就叫做闭包。而且再一个作用域中引用了另一个作用域的变量,那么这个变量就一直被引用而不被销毁,所操作的值就会被保留
相对全局变量,跨作用域调用
代码示例:
var abc=function(){
var i=0;
return function(){return ++i;};
}();
内部函数访问了外部函数的变量形成闭包,也就是说外部函数执行完毕后 变量i不会被释放而被内部函数一直引用着。
内部函数执行时访问的i永远是外部函数中i的最新值,而内部函数对i的每次操作也会对外部函数的i产生影响。
1,疑问:为什么i不会被清零?
答:为什么i不会被清0呢,首先应该明白全局变量的概念,当全局变量被定义以后,不管执行什么运算,全局变量最后的结果都会被保存在内存中不会被初始化。
在abc方法中,我们先对i赋了一个初始值0,然后return了一个function ,此时这个function相当于abc方法的子方法,此时由于i在子方法外,所以相对于子方法,i这个变量是一个全局变量,所以在子方法中,i会被保存在内存中,不会被垃圾回收机制清空,而子方法依赖于父方法abc,因此导致父方法中的i也不会被垃圾回收机制从内存中清除,这样就使得i会相当于一个全局变量一直递增.(另外:abc里面的i只会在第一次被初始化,接下来var i=0;都是不会执行的)

2,疑问:为什么闭包运行完了,引用变量还会驻留内存,不被释放呢?(释放内存跟引用有关,跟执行完成是否无关)
答:涉及全局变量概念的理解,应该说是相对全局变量,相对于闭包来说,i就是闭包的全局变量,所以就算闭包执行完,i相对于闭包还是个全局变量的角色驻留内存,除非手动删除这个变量。
你认为运行完之后释放了,恰恰相反运行完之后,由于ruturn function(){ ++i; }里边引用了i,所以不会被释放。释放的前提是,这个变量没有被引用,被垃圾回收器释放。(只要被别的函数引用了,就不被释放,驻留内存)
为什么加了个function(){}之后就没被释放,这就要从js的作用域讲起,js的作用域是按function(){}划分,就是以function(){}为一些变量,参数可访问的有限区域。
()的作用通俗的理解来说是调用。你定义了一段代码片段,不去调用就没有(),想调用就有();


改造函数消除闭包例子:
var abc=function(){
var i=0;
return function(num){
return ++num;
}(i);
}();
解释:最里面的函数保留的只是i的拷贝,而不是i对象的引用。这样,传递参数的时候,都是传递外部函数的i对象。而在执行++num的时候,他们解析的都是自己作用域内的num对象,而不是外部函数的i对象,因此不会出现自增长。

使用闭包要注意:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便
改变父函数内部变量的值。

闭包的应用场景,闭包怎么用,可以用来干什么?
闭包经常用于创建含有隐藏数据的函数,就像java对象里面的成员方法,用来访问对象的私有变量