1.标记清除:
当某个变量不再被使用时,该变量就会被回收.
2.引用计数
极少数浏览器(如IE)上针对引用类型数据的回收机制.
当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1,如果这个变量的值又被赋值给了另外一个变量(即两个变量的地址都指向同一个引用类型),则该值的引用次数+1。相反,如果包含这个引用类型的变量又取了另外一个值,则引用次数-1。当这个引用类型的引用次数变为 0 时,则说明无法再访问这个变量。当垃圾收集器下次再运行时,它就会释放引用次数为 0 的值所占用的内存。
在了解什么是闭包之前,我们先看下面的一个例子:
在上面这几行代码中,有一个局部变量a,有一个函数add, add里面可以访问到变量 a ,这就是一个闭包.
概念:
一个函数中嵌套另一个函数,内部函数使用了外部函数的参数或变量,就构成了闭包(这个内部函数就叫做闭包)。被内部函数使用的外部函数的参数或变量,不会被js的垃圾回收机制所回收 函数和函数内部能访问到的变量的总和就是一个闭包.
(function () { var a = 1; document.onclick = function () { var b = 10; console.info(++a); // 点击页面后依次输出 2 3 4 5 ... console.info(++b); // 点击页面始终都输出 11 } })()以上代码,局部变量在被使用后会被回收,但由于内部函数使用外部函数的了变量a,所以变量a不会被回收。而 变量b是一个局部变量且没有构成闭包,所以内部函数中 变量b 使用完后会被回收
补充:
在使用闭包的时候为什么会用到嵌套函数? function outer() { var a =123; function inner() { console.log(a); } return inner; } var in = outer(); in();因为我们需要的是局部变量,所以才将a放在一个函数里面,如果不把a 放在一个函数中,那么a就成了一个全局变量.这样就失去了使用闭包的目的 ----- 隐藏变量
所以函数套函数只是为了造出一个局部变量,跟闭包无关。
为什么需要return?如果不 return 就没有办法使用这个闭包, return 的目的就是为了能够在全局中访问到 inner 函数.
return inner 等价于 window.inner = inner
两条语句都是为了将inner函数暴露,以便于我们能够在全局中调用这个函数.
闭包常常用来间接的访问一个变量,通俗来讲就是隐藏一个变量.
一个例子:
假设我们此时正在做一个游戏,关于你还剩多少条命
如果不使用闭包,我们可以在全局中定义变量
window.lives = 10;这样做其实是很不好的,万一不小心改变了这个值怎么办??
我们不能让别人直接的访问到这个变量,如何解决?
使用一个局部变量,这样做也是不合适的,因为使用局部变量别人又访问不到…
这个时候就要请出来闭包了,暴露一个函数,让别人可以直接访问
(function() { var lives = 10; window.add = function () { lives++; } window.sub = function () { lives--; } }()) //增加一条命 add(); //减少 sub();那么在其他的 JS 文件,就可以使用 window.add() 来涨命,使用 window.sub() 来让角色掉一条命。
该函数中存在两个闭包:
闭包的性质在于每次重新引用函数的时候,闭包都是全新的
function outer(){ var count = 0; function inner(){ count++; console.log(count); } return inner; } var inn1 = outer(); var inn2 = outer(); inn1(); //1 inn1(); //2 inn1(); //3 inn1(); //4 inn2(); //1 inn2(); //2 inn1(); //5如果不了解闭包的话,我们就会理所当然的认为每次点击p会弹出响应的0,1,2,3,4,但实际的结果却是每次弹出都是5
方案一: 这时候就需要加一层闭包,i 以函数参数形式传递给内层函数:
这样的话就可以形成一个闭包,可以弹出我们想要的值.
点击222,弹出如下结果:
使用 ES6 - let 替换 var ,则不需要进行函数嵌套,如下:
<body> <p>000</p> <p>111</p> <p>222</p> <p>333</p> <script> var oP = document.querySelectorAll('p') for (let i = 0; i < oP.length; i++) { oP[i].onclick = function () { console.info(i); } } </script> </body>原理:let 是块级作用域,即每次for循环的 大括号内都是一个独立的作用域,而内部函数则是一个子作用域,也相当于作用域内嵌套子作用域(也类似形成了闭包),所以每次循环的 i 不会被回收。