前言
MDN对闭包的解释是这样的:一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。MDN文档
解释有点抽象,不好理解,现在我们用代码的形式来解释下。
一. 闭包概念解析
闭包让你可以在一个内层函数中访问到其外层函数的作用域
(1) 父对象的所有变量,对子对象都是可见的,子对象对父对象是不可见的
var a =1
function f1() {
a =2 ;
var b = 3;
}
console.log(b)
在f1函数里面是可以访问到函数外部变量a,但是在函数f1外部是访问不到函数内部的变量a的
(2)判断一个函数是不是闭包
f2(a) {
console.log(a,b)
}
function f1() {
var a = 1;
f2(a)
}
f1()
在上述代码中内部函数f2是不能访问到函数外部变量b,所以f2函数不是闭包
(3) 实现一个简单的闭包
function f1() {
function f2() {
}
}
上述代码 f2就是闭包,所以也验证了闭包让你可以在一个内层函数中访问到其外层函数的作用域这个概念
二. 为什么要用闭包?
闭包的作用主要有两点:
(1) 高继承和封装性;
(2) 避免全局变量污染。
示例代码如下
function computer() {
var baseNum = 10;
return {
plus: function(a,b) {
return a + b + baseNum
},
div: function(a,b) {
return a/b/baseNum
}
}
}
let res = computer();
res.plus(10,20)
高集成和封装性是因为可以将多个功能模块封装在一个函数里面,这样便于管理和维护
避免全局污染是因为假如函数内部改变了外部变量的值,而函数外部之后又用到了那个变量,这样在函数外部的使用可能不符合预期,所以闭包就是把该变量包裹在了一个局部的作用域里面,从而达到全局变量污染的目的
三. 闭包是怎么工作的?
上述的res变量为什么可以一直访问并改变computer函数里面的值?
(1)普通函数调用
function f1() {
var baseNum = 10;
function f2() {
baseNum++
console.log(baseNum)
}
f2()
}
f1();
f1();
根据js垃圾回收机制,f1每执行一次,里面的变量就会释放了,即f1函数里面的作用域链AO部分就断了
(2)闭包函数为啥可以保留之前的调用值
function f1() {
var baseNum = 10;
return function f2() {
baseNum++
console.log(baseNum)
}
}
var res = f1();
res();
res()
原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这个全局变量始终在内存中,这导致f2始终在内存中,而f2的存在依赖于f1,f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
四. 使用闭包的注意点
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)