1 介绍变量作用域
首先我们准备一个知识点变量作用域:
变量根据作用域分为两种:全局变量和局部变量。
全局变量可以在函数内部使用。局部变量不能在函数内的变量。 ----- JavaScript 高级编程
闭包有什么用?
1 扩展变量作用域,读取函数内部的变量
2 让这些变量的值永远留在内存中
简单的理解是一个作用域可以访问另一个函数内部的局部变量。
结案一
让我们看一个简单的闭包案例。
function fn1() {
var num = 10;
function fn2() {
console.log(num);
}
fn2();
}
fn1(); //输出结果10

我们已经多次看到或使用过这样的函数,但实际上这是一个闭包的应用。
我们可以通过 Chrome 的调试工具进行验证。

如图(看不到图片可以放大)
在Scope选项(Scope作用域的意思)中,有两个参数(全局全局作用域,局部局部作用域)。我在 fn1 函数调用(第 21 行)前面设置了一个断点来执行单步调试。当执行到fn2()时,Scope中会有一个额外的Closure(闭包)参数,表示生成了一个闭包。被访问的变量是num,包含num的函数是fn1。
fn1函数中的局部变量num是在fn2的作用域内访问的,所以此时fn1是一个闭包函数(访问变量的函数是闭包函数)
也有人说闭包是一种现象。一个作用域访问另一个函数中的局部变量。如果出现这种现象,就会发生闭包。我觉得这个理解没有问题。
关闭案例2
接下来,我们来看一个稍微复杂一点的闭包
function fn() {
var num = 10;
return function() {
console.log(num);
}
}
var f = fn();
// 上面这步类似于
// var f = function() {
// console.log(num);
// }
f();//输出结果10
在f=fn()的操作中,进行了num=10的赋值,给f赋值了一个匿名函数。这个函数是fn中return返回的匿名函数。请注意,这只是一项任务。并没有打电话。
然后在 f() 中调用匿名函数。这时候我们就可以在fn()函数外访问fn()中的局部变量num了。
$closure 扩展了变量的作用域,读取了函数内部的变量$
关闭案例三
首先来看一下这个关闭案例
var fn =function(){
var sum = 0
return function(){
sum++
console.log(sum);
}
}
fn()() //1
fn()() //1
//fn()进行sum变量申明并且返回一个匿名函数,第二个()意思是执行这个匿名函数
这里有一个小问题,为什么 sum 不自己增加?如果我想实现自增怎么办?
要回答这个问题,首先要了解js中的内存回收机制。 (具体见文后3Js内存回收机制)
我将在这里简要说明。执行 fn()() 后,fn()() 已经执行,没有其他资源引用 fn。这时候内存回收机制会认为fn是不需要的,会在内存中。释放它。
如何不被回收?
var fn =function(){
var sum = 0
return function(){
sum++
console.log(sum);
}
}
fn1=fn()
fn1() //1
fn1() //2
fn1() //3
此时fn1一直在引用fn(),此时不会释放内存,可以累加值。然后问题又来了。此类函数过多,会造成内存泄漏(内存泄漏、内存泄漏的知识点在4 内存泄漏、内存泄漏文章后面)
出现内存泄漏怎么办?我们可以手动发布
var fn =function(){
var sum = 0
return function(){
sum++
console.log(sum);
}
}
fn1=fn()
fn1() //1
fn1() //2
fn1() //3
fn1 = null // fn1的引用fn被手动释放了
fn1=fn() //num再次归零
fn1() //1
3 Js 内存回收机制
因为字符串、对象和数组没有固定的大小,当它们的大小已知时,它们可以动态分配用于存储。每次 JavaScript 程序创建字符串、数组或对象时,解释器都必须分配内存来存储该实体。只要像这样动态分配内存,最终必须释放内存,以便它们可以被重用。否则,JavaScript 解释器将消耗系统中所有可用内存并导致系统崩溃。
目前主流浏览器常用的垃圾回收方式有两种:标记移除和引用计数。
1 个标签清除

这是 JavaScript 中最常用的垃圾回收方法。当变量进入执行环境时,将变量标记为“进入环境”。从逻辑上讲,进入环境的变量所占用的内存永远无法释放,因为只要执行流程进入相应的环境,它们就可能被使用。当一个变量离开环境时,它被标记为“离开环境”。
2 引用计数
引用计数的意义在于记录每个值被引用的次数。当声明一个变量并为该变量分配一个引用类型时,对该值的引用次数为1。反之,如果包含对该值的引用的变量得到另一个值,则对该值的引用次数减少由一个。当引用数变为0时,表示没有办法访问这个值,所以可以回收它所占用的内存空间。这样,垃圾收集器下次运行时,就会释放引用计数为0的值所占用的内存。
4 内存溢出、内存泄漏、内存溢出
内存溢出一般是指当一个程序执行时,该程序会向系统请求一定的内存。当系统实际内存小于所需内存时,会导致内存溢出
内存溢出的结果是之前保存的数据会被覆盖或者后面的数据没有地方保存
内存泄漏
内存泄漏是指一些变量在程序执行的时候没有及时释放,一直占用内存
而这种占用内存的行为称为内存泄漏。
作为普通用户,根本没有内存泄漏。真正有害的是内存泄漏的累积,最终会耗尽系统的所有内存。从这个角度来看,一次性内存泄漏并没有什么害处,因为它不会累积。
如果内存泄漏不断累积,最终会导致内存溢出问题
5 总结什么是闭包?
闭包就是一个函数(一个作用域可以访问另一个函数的局部变量)
闭包的作用是什么?
1 扩展变量作用域,读取函数内部的变量
2 让这些变量的值永远留在内存中
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-380822-1.html
很期待
美国佬喜欢欺负小字辈
有人需要便宜的