zoukankan      html  css  js  c++  java
  • JavaScript:闭包

    闭包

    闭包:指有权访问另一个函数作用域中的变量的函数。

    创建闭包的常见方式就是在一个函数内部创建另一个函数:

    function createComparisonFunction(propertyName) {
        return function (obj1, obj2) {
            // 访问了外部函数中的变量
            var value1 = obj1[propertyName];
            var value2 = obj2[propertyName];
    
            if (value1 < value2) {
                return -1;
            } else if (value1 > value2) {
                return 1;
            } else {
                return 0;
            }
        };
    }

    上面的obj1、obj2访问了外部函数的变量propertyName。之所以能访问到这个变量,是因为内部函数的作用域中包含createComparisonFunction()的作用域。

    当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后,使用arguments和其他命名参数的值来初始化函数的活动对象。

    在函数执行过程中,为读取和写入变量的值,就需要在作用域链中查找变量。

    function compare(value1, value2) {
        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    }
    
    var result = compare(5, 10);

    上面先调用了compare()函数,然后又在全局作用域调用了它,当调用compare()时,会创建一个包含arguments、value1和value2的活动对象。全局执行环境的变量对象在compare()执行环境的作用域链中则处于第二位。

    compare()函数执行时的作用域链:

    在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。因此createComparisonFunction()函数内部定义的匿名内部函数的作用域链中,实际上将会包含外部函数createComparisonFunction()的活动对象。

    var compare = createComparisonFunction("name");
    var result = compare({name: "Nicholas"}, {name: "Greg"});

    下图展示了代码执行时,包含函数与内部匿名函数的作用域链。

    匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就可以访问在createComparisonFunction()中定义的所有变量。另外,在createComparisonFunction()执行完,它的活动对象不会被销毁,从图中可以看出,匿名函数还引用了这个活动对象。当createComparisonFunction()函数返回时,其执行环境的作用域链会被销毁,但它的活动对象仍会留在内存中;匿名函数被销毁后,createComparisonFunction()的活动对象才会销毁。

    // 创建函数
    var compareNames = createComparisonFunction("name");
    
    // 调用函数
    var result = compareNames({name: "Nicholas"}, {name: "Greg"});
    
    // 解除对匿名函数的引用(释放内存)
    compareNames = null;

    首先,创建的比较函数被保存在compareNames,将compareNames设置为null,解除了该函数的引用,就可以进行清除了。

    闭包与变量

    闭包保存了整个变量对象,但只能取得包含函数中任何变量的最后一个值。

    示例:

    function createFunctions() {
        var result = new Array();
        
        for (var i = 0; i < 10; i++) {
            result[i] = function () {
                return i;
            };
        }
        return result;
    }

    上面的例子中看似每个函数都返回自己的索引值,实际上,每个函数都返回10。因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。

    通过创建另一个匿名函数强制让闭包的行为符合预期,如下:

    function createFunctions() {
        for (var i = 0; i < 10; i++) {
            return [i] = function (num) {
                return function () {
                    return num;
                };
            }(i);
        }
        return result;
    }

    this对象

    this对象在运行时是基于函数的执行环境进行绑定的,在全局函数中,this等于window;当某个对象的方法调用时,this等于那个对象。但是,匿名函数的执行环境具有全局性,其this对象指向window。

    看一个例子:

    var name = "The Window";
    
    var object = {
        name: "My Object",
    
        getNameFunc: function () {
            return function () {
                return this.name;
            };
        }
    };
    
    alert(object.getNameFunc()());  // "The Window"

    上面的例子中首先创建了一个全局变量name,又创建了一个包含name属性的对象。这个对象包含一个方法:getNameFunc(),它返回一个匿名函数,而匿名函数又返回this.name。由于getNameFunc()返回一个函数,因此调用object.getNameFunc()()就会调用它返回的函数,结果为:this.name。然而,返回的字符串是"The Window"。

    为什么匿名函数没有取得其包含作用域的this对象呢?

    每个函数在函数在被调用时都会获取两个变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,不可能访问到外部函数中的这两个变量。

    把外部作用域中的this对象保存到一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

    var name = "The Window";
    
    var object = {
        name: "My Object",
    
        getNameFunc: function () {
            var that = this;
            return function () {
                return that.name;
            };
        }
    };
    
    alert(object.getNameFunc()());  // "The Window"
  • 相关阅读:
    Fidder4 顶部提示 “The system proxy was changed,click to reenable fiddler capture”。
    redis 哨兵 sentinel master slave 连接建立过程
    虚拟点赞浏览功能的大数据量测试
    python基础练习题(题目 字母识词)
    python基础练习题(题目 回文数)
    python基础练习题(题目 递归求等差数列)
    python基础练习题(题目 递归输出)
    python基础练习题(题目 递归求阶乘)
    python基础练习题(题目 阶乘求和)
    python基础练习题(题目 斐波那契数列II)
  • 原文地址:https://www.cnblogs.com/bbc66/p/9498718.html
Copyright © 2011-2022 走看看