我一直以为 闭包和原型链的学习是个抽丝剥茧的过程,这个过程痛苦且漫长 是真的不容易一下子理解的。
今天读了《你不知道的javaScript》 ,我觉得闭包讲的挺好的,还是总结一下吧。 变成自己的技能树一部分;
作者的话 :
对于那些有一点 JavaScript 使用经验但从未真正理解闭包概念的人来说,理解闭包可以看作是某种意义上的重生,但是需要付出非常多的努力和牺牲才能理解这个概念。
闭包就好像从 JavaScript 中分离出来的一个充满神秘色彩的未开化世界,只有最勇敢的人 才能够到达那里。但实际上它只是一个标准,显然就是关于如何在函数作为值按需传递的 词法环境中书写代码的。
闭包是基于词法作用域书写代码时所产生的自然结果,你甚至不需要为了利用它们而有意 识地创建闭包。闭包的创建和使用在你的代码中随处可见。你缺少的是根据你自己的意愿 来识别、拥抱和影响闭包的思维环境。
最后你恍然大悟:原来在我的代码中已经到处都是闭包了,现在我终于能理解它们了。理 解闭包就好像 Neo3 第一次见到矩阵 一样。
我们经常听人说闭包的强大 ,能实现这个看似一些不可能完成的任务; 优雅且高贵 。
这里 ,定义一下 广义上的闭包: 如果曾经形成了自己小天地(专属作用域)的 都算是闭包;
技术意义上的闭包: 在广义的基础上,能够把专属作用域的变量拿出来为我所用的,体现出强大的一面。
作者是这么定义的:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用 域之外执行。
还举了俩个小栗子,来说明
demo1 :
function foo() { var a = 2;
function bar() { console.log( a ); // 2
}
bar(); }
foo();
demo2:
function foo() { var a = 2;
function bar() { console.log( a );
}
return bar; }
var baz = foo();
baz(); // 2 —— 朋友,这就是闭包的效果。
demo1 是闭包吗? 曾经是吧。一调用那一瞬间是个闭包。之后就没有了。
demo2 这就是一个标准的闭包, 闭包了,并且体现出了效果。且 一般说的的闭包 更多的应该是值的这一种。
demo3
var a = 2;
(function IIFE() { console.log( a );
})();
demo4
(function IIFE(a) {
console.log( a );
})(3);
demo5
var a = (function IIFE() {
var b=5;
var c=6;
var d={b,c};
return d
})();
a.b // 5
a.c // 6
IIFE函数一般来说算是 大家说的闭包 ,但是作者不同意的观点,我表示同意作者的观点也不同意这种观点,
demo3 技术来讲只算是广义上的闭包;
demo4 这种拥有了自己变量和自己的专属作用域,但是在内存也就是一瞬间。所以也算不得;
demo5这种就是闭包了 为我所用并且使用了单例模式 还返回了一个对象包装API 来供我们使用这个特性。
简单的原理就是
我们知道引擎有垃 圾回收器用来释放不再使用的内存空间。由于看上去第一层函数的内容不会再被使用,所以很 自然地会考虑对其进行回收。
而闭包的“神奇”之处正是可以阻止这件事情的发生。事实上内部作用域依然存在,因此 没有被回收。所以可以被利用,乃至把这个特性放大去利用产生了各种神奇的效果。
简而言之: 1,符合最小授权 不污染全局变量, 2,保存 专属的独特空间为我所用。自己为自己建造了一艘豪华游艇。
闭包的应用 :模块
这个 功能就是做 插件用的最多。强大的一面开始展现;
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(); // cool
foo.doAnother(); // 1 ! 2 ! 3
一个模块有自己专属的功能和方法,最常见的实现模块模式的方法通常被称为模块暴露,专属的模块的实现方式,
这边我需要几个不同的模块 我就可以调用几次生产
加以改进: 更多的情况下
var foo = (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
}; })();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
单例模式的生成,往往在 项目组我们更多的插件也是 单例,IIFE 页面加载的时候自动生成一个。
然后我们就可以开心的使用这个实例了;
更加加以改进:
var foo = (function CoolModule(id) {
function change() {
// 修改公共 API
publicAPI.identify = identify2;
}
function identify1() {
console.log( id );
}
function identify2() {
console.log( id.toUpperCase() );
}
var publicAPI = {
change: change,
identify: identify1
};
return publicAPI;
})( "foo module" );
foo.identify(); // foo module
foo.change();
我们 在最后返回的时候 给包装到一个对象 并且把这个对象 声明一个标签加以保存; 类似的 匿名函数和非匿名函数之间的好处,
这样我们就可以去拿到这个返回的 对象并且 对其内部做一些改变了,拥有更多的主动权。
。
let 的 实现其实 也是一个闭包。 和块级作用域配合起来, 强的一匹。
模块管理 工具也是闭包的实现 。现在我们用的模块工具 都是 import 和export 所以这方面不赘述。