闭包特烦恼

0. 前言


2016年马上就要过去了,首先,提前祝大家元旦快乐,在这最后一个工作日里我还在敲着代码,好了,说一下今天我要分享的"闭包",闭包是谁?干什么的?,有什么优点?什么缺点?闭包就是一个包啊!!!-然后...

娇羞.jpg


1. 简介


1. 什么是闭包呢?
外部函数返回的并持有外部变量的内部函数就是闭包。是不是还没懂,那我就换种说法,(闭包就是指有权访问另一个函数作用域中的变量的函数)
2. 用闭包干什么?
用闭包来突破作用域链,让它可以在外面可以使用内部的变量的方法
3. 优点
  • 避免污染全局环境
  • 实现封装,防止变量跑到外层作用域中,发生命名冲突
  • 匿名自执行函数,匿名自执行函数可以减小内存消耗
4. 缺点

数据长期的驻留在内存中,造成了内存的极大浪费,在IE浏览器下,特别容易崩溃。所以闭包特烦恼,用之需谨慎。

点我
没事别BB,有事用图说,首先感谢美女给我画的图,三克油
闭包.png

2. 代码实现


2.1 作用域链
//作用域链:环境对象中定义的变量,会放到作用域中,形成一个链式结构。
        var a = 10;
        function F() {
            var b = 20;
            //内部函数:函数内部定义的函数
            function N() {
                var c = 30;
                return a + b + c;
            }
            return N();
        }
        //验证N中是否都能使用所有的链上变量
        console.log(F());//输出 60
图 1
作用域链.png
首先,我们把全局作用域G,我们可以把它当做可以包含一切的宇宙,其中,包含全局变量 (如a) 和函数 (如F) ,每个函数也都会有属于自己的一块私用空间,用以储存一些别的变量 (如b) 和内部函数 (如N)。


2.2 突破作用域链


代码1
        var a = 10;
        function F() {
            var b = 20;
            function N(){
                return b;
            }
            return N;
        } 
        var M = F();
        console.log(M());//输出 20

代码2
        与上面的代码功能一样,只不过实现过程有些区别
        var inner;
        var a = 10;
        function F() {
            var b = 20;
            function N(){
                return b;
            }
            inner = N;
        }
        F();
        console.log(inner());//输出 20
图 2
突破作用域链.png
N() 仍然可以访问 F() 空间并使用变量b,虽然现在 N() 和 a 处于同一块空间,但 a 不能访问 b。


2.3 闭包的应用


2.3.1. 循环中的闭包
function F() {
            var arr = [];
            for (var i = 0; i < 3; i++) {
                arr[i] = function(){
                    return i;
                };
            }
            return arr;
        }
        var str = F();
        console.log(str[0](), str[1](), str[2]());//输出 3 3 3
  • arr中每一项执行时,都会去上级作用域寻找i,而i在for循环执行结束后就已经变成了3,所以arr中每一项执行的结果都是一样的。
  • 闭包本身不保存上一作用域中变量的值,当使用时是去上面的作用域中查找相同名字变量,使用最近那一层作用域中的变量
2.3.2. 解决
function F() {
            var arr = [];
            for (var i = 0; i < 3; i++) {
                arr[i] = (function(x){
                    return function(){
                        return x;
                    };
                })(i);
            }
            return arr;
        }
        var str = F();
        console.log(str[0](), str[1](), str[2]());//输出0 1 2

arr中每次添加新项是都会使得自执行函数执行,并将i作为参量传入了自执行函数,关键点是 function(x){...}(i)中第一个x是函数的形参,是私有变量,与外面的i没有关系,被私有作用域保护起来了,第二个i才是函数中外面的i(也就是说第一个x只是一个迷惑人的量,你改成k也是一样的结果,只不过是把i赋给k而已)这样一来,每次触发自执行函数时,都相当于将当前循环的变量i存储了下来。

2.3.3. getter方法和setter方法
getter和setter使你可以快速获取或设置一个数据。

为了变量的安全,一般我们不允许直接访问变量,通过中间的方法间接的访问

//getter获取
var getNum;
(function(){
    var num = 0;
    //getter方法
    getNum = function(){
        return num;
    };
})();
console.log(getNum());// 输出 0;
//setter设置
        var setNum;
        var getNum;
        (function(){
            var num = 0;
            //setter方法
            setNum = function(x){
                //安全的考虑
                if (typeof x === "number") {
                    num = x;
                }
            };
            //getter方法
            getNum = function(){
                return num;
            };
        })();
        setNum(100);
        console.log(getNum());//输出 100;
2.3.4. 数组的迭代器
var arr = [1,2,3,4,5];
        function setUp(x){
            var i = 0;
            return function(){
                if (x.length == i - 1) {
                    i = 0;
                }
                return x[i++];
            };
        }
        var next = setUp(arr);
        console.log(next());//输出 1
        console.log(next());//输出 2
        console.log(next());//输出 3
        console.log(next());//输出 4
        console.log(next());//输出 5
当然迭代不能就这一种方法,还有很多,我就不过多的说了,现在我们使用"下一个是谁"的想法去遍历刚才的数组,每次调用 next() 的时候 i++,这样我们就知道当前的值,so,我们也就知道"下一个是谁"


3. 结束语

好了,闭包特烦恼 也就写到这里了,如果你能看我的文章看到这里,那你可以说喜欢我,这是真爱啊!!!嘿嘿,希望我写的对你有点帮助,最后祝大家假期愉快,分享,点赞,!!!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容