前言: 最近由于公司项目太忙, 很久没有更新博客了, 加上之前就一直说要发表一篇有关闭包的博客帮助小伙伴们好好的理解一些 JavaScript 中的难点. 所以, 今天趁着国庆假期前赶紧写了去, 写完国庆好好出去浪个够.
首先, 必须要提的就是闭包它绝对算的上是 JavaScript 中的一大难点, 当然也是一大重点. N 多高级程序都需要或者必须用到闭包才能得以实现. 参考了 N 篇很牛叉的对于闭包理解的文章, 接下来我将陈述一下鄙人自己对于闭包的理解, 希望可以帮助小伙伴们通俗切入闭包这个点.
1, 变量作用域
理解闭包很重要的一点就是需要先理解 JavaScript 特殊的变量作用域.
而变量作用域无非两种形式, 全局变量和局部变量. 而在 JavaScript 中, 所有的函数它都可以在其内部访问到全局变量.
- var n = 123;
- function test1(){ alert(n);
- }
- test1(); //123
而在函数外部也无法读取函数内的局部变量.
- function test1(){
- var n=123;
- }
- test1();
- alert(n); // Uncaught ReferenceError: n is not defined
当然在定义变量的时候, 一定要记住加上 var 关键字, 不然, JavaScript 会默认你定义了一个全局变量.
- function test1(){
- n=123;
- }
- test1();
- alert(n); // 123
2, 函数外部访问局部变量
很多时候我们需要在一个函数中去访问另外一个函数内部的局部变量, 可是上面又说了一个函数内部的局部变量是不允许被其他函数访问的. 怎么办呢?
那我们就需要在函数内部在定义一个函数, 这样就可以在其内部函数中访问到它内部的局部变量了. 上代码理解.
- function test1(){
- // 函数 test2 就被包括在函数 test1 内部, 这时 test1 内部的所有局部变量, 对 test2 都是可见的
- var n=123;
- function test2(){
- // test2 内部的局部变量则不能被 test1 访问
- // 这就是 Javascript 语言特有的 "链式作用域" 结构 (chain scope), 子对象会一级一级地向上寻找所有父对象的变量. 所以, 父对象的所有变量, 对子对象都是可见的, 反之则不成立.
- var n1 = 321;
- alert(n);
- }
- //alert(n1); // error
- return test2;
- }
- var result=test1();
- result(); // 123
而上面代码中的 test2 就是一个闭包, 它是一种能够读取其他函数内部变量的函数, 或者直接理解为定义在一个函数内部的函数.
3, 闭包的用途
闭包可以用在很多地方. 但它最大的用处有两点. 第一点是以上提到的, 访问其他函数内部的局部变量. 还有一个很重要的用途则是让这些变量始终保存在内存中. 不多解释, 直接看代码理解
- function test1(){
- /**
- * test1 是 test2 的父函数, 而 test2 被赋给了一个全局变量 result, 这导致 test2 始终在内存中
- * 而 test2 的存在依赖于 test1, 因此 test1 也始终在内存中
- * 这样 test1 中的局部变量就不会在调用结束后, 被垃圾回收机制回收.
- */
- var n=123;
- // nAdd 前面没有 var 关键字, 它是一个全局变量. nAdd 的值是一个匿名函数, 而这个匿名函数本身也是一个闭包
- // 它相当于一个 setter, 可以在函数外部对函数内部的局部变量进行操作.
- nAdd = function(){
- n+=1
- }
- function test2(){
- alert(n);
- }
- return test2;
- }
- var result=test1();
- result(); // 123
- nAdd();
- result(); // 124
4, 闭包使用中需注意的问题
1) 由于闭包会使得函数中的变量都被保存在内存中, 内存消耗很大, 所以不能滥用闭包, 否则会造成网页的性能问题, 在 IE 中可能导致内存泄露. 解决方法是, 在退出函数之前, 将不使用的局部变量全部删除.
2) 闭包会在父函数外部, 改变父函数内部变量的值. 所以, 如果你把父函数当作对象使用, 把闭包当作它的公用方法, 把内部变量当作它的私有属性, 这时一定要小心, 不要随便改变父函数内部变量的值.
5, 练习思考题
当你可以理解以下两段代码运行结果时, 那么恭喜你, 你已经理解了闭包的运行机制了.
- // 代码一
- var name = "The Window";
- var object = {
- name : "My Object",
- getNameFunc : function(){
- return function(){
- return this.name;
- };
- }
- };
- alert(object.getNameFunc()());
- // 代码二
- var name = "The Window";
- var object = {
- name : "My Object",
- getNameFunc : function(){
- var that = this;
- return function(){
- return that.name;
- };
- }
- };
- alert(object.getNameFunc()());
好了, 文章最后. 还是那句话, 如果觉着可以帮助到小伙伴的话, 求点个赞哦. 若觉着哪里有说错或者写错的地方, 还请小伙伴们轻喷, 但是欢迎小伙伴随时指正博客中的错误然后大家一起交流探讨!(*^__^*)
来源: https://yq.aliyun.com/articles/615144