zoukankan      html  css  js  c++  java
  • 也谈JavaScript闭包

    闭包对于很多JavaScript初学者来说,都是比较难以理解的一个概念。其实,闭包并不是那么难以掌握的,理解闭包,只需要学会3个的基本事实


    首先我们来看第一个事实,JavaScript允许当前函数引用外部定义的变量,如下:
    function makeSandwich() {
        var magicIngredient = "peanut butter";
        function make(filling) {
            return magicIngredient + " and " + filling;
        }
        return make("jelly");
    }
    makeSandwich(); // "peanut butter and jelly"
    上述代码中,函数make是可以使用magicIngredient这个变量的。这是因为,JavaScript首先会在make函数内部以及他的原型上寻找magicIngredient这个变量,结果没有找到,于是,他就会沿着词法环境(或者说是作用域链)向它上一级作用域寻找,于是,就在makeSandwich里找打了。
     
    接下来,我们再来看一下第二个事实,即使外部函数已经返回,当前函数依然可以使用外部函数的变量:
    function sandwichMaker() {
        var magicIngredient = "peanut butter";
        function make(filling) {
            return magicIngredient + " and " + filling;
        }
        return make;
    }
    var f = sandwichMaker();
    f("jelly"); // "peanut butter and jelly"
    f("bananas"); // "peanut butter and bananas"
    f("marshmallows"); // "peanut butter and marshmallows"
    这个例子与第一个例子几乎是一样的,只是,make函数不是直接在sandwichMaker里面直接执行,而是将他返回到函数外部,然后才执行。即使函数已经返回到外部了,f函数(也即make函数,其实他们的引用是一样的)依然记住magicIngredient变量的值。
     
    这是如何工作的呢?答案是,JavaScript的函数值包含的信息比它执行时所需要的信息还要多。而且,JavaScript函数内部存储了可能会用到的在外部定义的变量的引用(注意是引用,而不是值)。那些在其所涵盖的作用域内跟踪变量的函数称为闭包。这里的make函数就是闭包了,它引用了两个外部变量,magicIngredient和filling。每当make函数被调用时,都能够用到这两个变量,因为,他的内部已经存储了他们的引用( 指针)。
     
    函数可以引用其作用域内的任何变量,包括参数和和外部函数变量,上面的代码可以改成如下形式,使它更为灵活通用:
    function sandwichMaker(magicIngredient) {
        function make(filling) {
            return magicIngredient + " and " + filling;
        }
        return make;
    }
    var hamAnd = sandwichMaker("ham");
    hamAnd("cheese"); // "ham and cheese"
    hamAnd("mustard"); // "ham and mustard"
    var turkeyAnd = sandwichMaker("turkey");
    turkeyAnd("Swiss"); // "turkey and Swiss"
    turkeyAnd("Provolone"); // "turkey and Provolone"
    JavaScript还提供了一种通过字面量来创建闭包的方法,那就是函数表达式,如下:
    function sandwichMaker(magicIngredient) {
        return function(filling) {
            return magicIngredient + " and " + filling;
        };
    }
    我们会发现,这个函数表达式是一个匿名函数,但是,这并无影响的,因为,我们并没有在里面调用执行它。
     
    最后,我们来看一下第三个事实,闭包可以更新外面变量的值。
     
    事实上,闭包内部存储的是外部变量的引用地址,而不是外部变量的值的副本。光说是很难理解的,下面我们来看一个例子:
    function box() {
        var val = undefined;
        return {
            set: function(newVal) { val = newVal; },
            get: function() { return val; },
            type: function() { return typeof val; }
        };
    }
    var b = box();
    b.type(); // "undefined"
    b.set(98.6);
    b.get(); // 98.6
    b.type(); // "number"
    这个例子,box函数可以返回一个对象,这个对象具有3个闭包,分别是set,get,type,他们都可以访问到val这个变量,其中,set是设置val的值,get是获取val的值,type是获取val的值的类型。
     
    总结:
    1.函数可以引用定义在其外部的变量
    2.闭包比创建他们的函数具有更长的生命周期
    3.闭包内部存储了外部变量的指针,既可以读取他们,也可以修改。
  • 相关阅读:
    Git:本地文件到远程仓库
    logstash.conf 配置:input kafka,filter,output elasticsearch/mysql
    PowerDesigner根据Excel设计数据表结构 Excel表结构导入PowerDesigner
    VBScript PowerDesigner使用手册
    PowerDesigner导出数据表结构到Excel 一个表一个Sheet 带链接目录
    PowerDesigner导出数据表结构到Excel 所有表结构在同一个Sheet中
    Windows下如何用virtualenv创建虚拟环境
    解决ValueError: day is out of range for month的问题
    正则表达式
    移动端库和框架
  • 原文地址:https://www.cnblogs.com/yugege/p/4975160.html
Copyright © 2011-2022 走看看