就我而言,一开始接触闭包,感觉是个很抽象的概念。
直接看程序吧
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>闭包</title>
</head>
<body>
<script>
function foo(){
var a=2;
function bar(){
console.log(a);
}
return bar;
}
var baz=foo();
baz();
</script>
</body>
</html>
运行结果:
运行结果为2
在上述程序中,bar()的词法作用域能够访问foo()的内部作用域,然后将bar()函数本身当作一个值类型进行传递。
在foo()执行后,其返回值赋值给变量baz并调用baz()函数。
bar()被正常执行了,但是,它是在自己定义的词法作用域以外的地方执行。
在一个函数执行后,因为引擎有垃圾回收器来释放不再使用的内存空间,所以我们通常都会期待它的整个内部作用域都被销毁。
闭包就可以阻止这件事的发生,咱们再看看上述代码,注意观察bar()声明的位置,bar()在foo()函数内部声明,它拥有涵盖foo()内部作用域的闭包,从而使得该作用域能够一直存活,保证了bar()在之后任何时间进行引用。
所以:bar()依然持有对该作用域的引用,这个引用就叫作闭包。
差不多了解了闭包之后,我们来看看模块
观察如下程序:
<!DOCTYPE html>
<html>
<!--
作者:offline
时间:2019-11-10
描述:模块
-->
<head>
<meta charset="UTF-8">
<title>模块</title>
</head>
<body>
<script>
function CoolModule(){
var something="cool";
var another=[1,2,3];
function doSomething(){
console.log(something);
}
function doAnother(){
console.log(another.join("!"));
}
return {
doSomething:doSomething(),
doAnother:doAnother()
};
}
var foo=CoolModule();
foo.doSomething();
foo.doAnother();
</script>
</body>
</html>
运行结果:
如上模式就被 称为模块
现在我们来分析以下上述程序:
我们要通过调用CoolModule()函数来创建一个模块实例
通过观察,发现CoolModule()返回的是一个用对象字面量语法来表示的对象,即:
return {
doSomething:doSomething(),
doAnother:doAnother()
};
这个返回的对象含有的是对内部函数的引用而不是对内部数据变量的引用。
对象类型的返回值最终赋值给外部变量foo,然后通过它来访问API中的属性方法,即:
foo.doSomething();
foo.doAnother();
在上述程序中:
doSomething()和doAnother()具有涵盖模块实例内部作用域的闭包,它是通过调用CoolModule()实现的。
总结:
模块模式的必要条件:
(1)一定得有外部的封闭函数,并且该函数至少被调用一次,而且每次调用都会创建一个新的模块实例
(2)封闭函数必须返回至少一个内部函数,只有这样,内部函数才能在私有作用域中形成闭包,并且可以访问或修改私有的状态。