浅谈javascript中的闭包

引入定义:闭包只有权访问另一个函数中的作用域中的函数。

简单点说,就是当某函数a执行完毕后,闭包不会使得GC(JavaScript的回收机制)去回收a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

代码示例:

window.onload = function(){
        function createComparisonFunction(propertyName){
            return function(object1, object2){
                var value1 = object1[propertyName];
                var value2 = object2[propertyName];
                console.log(arguments);
                if(value1 < value2){
                    return –1;
                }else if(value1 > value2){
                    return 1;
                }else{
                    return 0;
                }
            };
        }
        var compareNames = createComparisonFunction("name");
        var result = compareNames({name:"Nicholas"},{name:"Greg"});

在此例中,当调用玩createComparisonFunction函数后,局部活动对象,即

调用createComparisonFunction这个函数是产生的活动对象理应被销毁,但是如我们在下面调用的语句,compareNames依然成功调用,而注意到,我们在匿名函数内(3行)是引用了createComparisonFunction的西参数的,其实这就是闭包的一个细微体现吧。
不信,咱再证明一下无妨:在上面代码的第五行,不是有一个控制带输出语句吗,其打印的是匿名函数的匿名参数arguments,结果附上:

从上图中,我们不难看出,在匿名函数的<function scop>中,保存有作用域链,其中就有createComparisonFunction的形式参数propertyName:“name”。

闭包注意事项1: 闭包与变量:

在闭包中的变量有其特殊性,但其实深究一下,也其实挺普遍的:

上代码:

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

最终输出结果:  每一次输出都为10

解释:而当createFunction()函数返回后,变量i的值是10,此时每一个函数都引用着保存变量i的同一个变量对象,所以……

当然,我们可以通过一个非常巧妙的方法来解决这个问题:

function createFunctions(){
            var result = new Array();
            for(var i = 0; i < 10; i++){
                result[i] = function(num){   //用num来保存i的初始值
                    return function(){
                        return num;
                    }
                }(i);
            }
            return result;
        }
        var results = createFunctions();
        for(var i = 0; i < 10; i++){
            console.log(results[i]());   //0,1,2,3,4,5,6,7,8,9
        }

方法之妙,不言而喻,也许这就是语言之妙吧。

说完闭包,我们再来谈谈与其密切相关的东西,作用域链和活动对象:

官方:  当某个函数被调用时,会创建一个执行环境及相应的作用域链,然后,使用arguments和其它命令参数的值来初始化函数的活动对象,但在作用域中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,知道作用域终点的全局执行环境。

嘛意思呢:哥总结为下:

1:函数一创建,即产生作用域链。

2:作用域链保存在arguments或其他参数中(见本文上面的截图)。

3:何为作用于链:

引入作用域:任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

作用域链:即为作用域的集合。其本质上是一个指向变量对象的指针列表,它只引用但不包含变量对象。

上代码:   test1:

var name = "The Window";
    var num = 100;   //   全局变量对象
    var object = {
        name: "Ny Object",
        //活动对象开始-------本地活动对象------------------
        getNameFunc: function(num){
            return function(){
                return num;
            };
        }
//        活动对象结束:------------------------------------------------------------------------
    };
    console.log(object.getNameFunc(500)());    //500

test2:

var name = "The Window";
    var num = 100;   //   全局变量对象
    var object = {
        name: "Ny Object",
        //活动对象开始-------本地活动对象-------------------------------------------------
        getNameFunc: function(num){
            return function(num){
                return num;
            };
        }
//        活动对象结束:------------------------------------------------------------------------
    };
    console.log(object.getNameFunc(500)(50));    //50

test3:

var name = "The Window";
    var num = 100;   //   全局变量对象
    var object = {
        name: "Ny Object",
        //活动对象开始-------本地活动对象-------------------------------------------------
        getNameFunc: function(){
            return function(){
                return num;
            };
        }
//        活动对象结束:------------------------------------------------------------------------
    };
     console.log(object.getNameFunc()());   //100

从上面三个代码的测试结果不难看出,本地活动对象优先,然后一级一级的网上寻找目标变量(当函数要访问某个变量时)。

其完整的寻找路径(最长的时候)即为一个作用域链。

时间: 2024-12-26 16:03:07

浅谈javascript中的闭包的相关文章

浅谈JavaScript中的原型模式

在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">//工厂模式 function createPerson(name,age,job) { var o = new Object; o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); } retur

浅谈JavaScript中继承的实现

  谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我已就在JavaScript中对象创建的方法做了一些总结,下面就其继承来道说一二:   1:原型链继承: 每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象内部的指针(默认的原型,所有默认类型都继承了Object,而这个继承也是用过原型链实现) fu

浅谈javascript中的For in语法

相信大家都使用过javascript中的for循环,主要用来遍历数组对象,方便执行重复操作,体现代码的重用性.但是,应为数组的索引一般是整 型的数字,当遇到JSON对象或者object对象时,就不能使用for循环遍历了,应当使用for in函数遍历对象,这里就谈谈个人对for in的理解. 首先,虽然叫For in语法但关键字还是用for,这个语法还可以用来遍历对象,拿到的是对象的属性名称,然后通过对象名[属性名称]就可以拿到对象.个人觉得,理解这个语法的本质,关键在于理解每次循环得到的到底是什

浅谈javascript中的call、apply、bind

apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念. 先来一个栗子: function fruits() {} fruits.prototype = { color: "red", say: function() { console

浅谈JavaScript中的函数问题

前面的话:JavaScript可运行在所有主要平台的主流浏览器上,也可运行在每一个主流操作系统的服务器端上.所以呢,要想成为一名优秀的全栈工程师,必须懂得JavaScript语言.这是我整理的JS的部分函数问题,供大家参考借阅,有不妥的地方也请多多指教. 1.函数的三要素    1.1 函数的功能   1.2 函数的参数 a. 形参——定义函数的时候,没有实际的值,给实参占位 b. 实参——调用函数的时候,有实际的值: c. 当调用函数的时候会把实参复制一份传递给函数 d. 函数调用的时候,实参

浅谈javascript中的包装对象

javascript中的对象类型分为内置类型和对象类型,其中内置类型包括sting number boolean null undefined五种:对象类型包括Array Function regExp Date 等等,统称为Object类型.我们知道在一个对象中包含一系列属性名/属性值的集合,可以通过"."来访问对象的属性或方法,如: 1 window.onload=function(){//可执行代码} 但我们常常可以看到这样的代码: 1 var str="hello w

A1—浅谈JavaScript中的原型

原型是什么?想要了解这个问题,我们就必须要知道对象. 对象 根据w3cschool上的介绍:对象只是带有属性和方法的特殊数据类型. 我们知道,数组是用来描述数据的.其实呢,对象也是用来描述数据的.只不过有一点点的区别,那就是数组的下标只能是数字.所以,数组最好只用来装同样意义的内容.比如说[1,2,3,4,5]或者["a","b","c","d","e"]等.因为他们的表达的含义是一样的.那么如何表达含义不

浅谈JavaScript中的string拥有方法的原因

我们都知道,JavaScript数据类型分两大类,基本类型(或者称原始类型)和引用类型. 基本类型的值是保存在栈内存中的简单数据段,它们是按值访问的.JS中有五种基本类型:Undefined.Null.Boolean.Number和String. 引用类型的值是保存在堆内存中的对象,它的值是按引用访问的.引用类型主要有Object.Array.Function.RegExp.Date. 对象是拥有属性和方法的,所以我们看到下面这段代码一点也不奇怪. var favs=['鸡蛋','莲蓬']; f

A1—浅谈JavaScript中的原型(二)

原型是什么?想要了解这个问题,我们就必须要知道对象. 对象 根据w3cschool上的介绍:对象只是带有属性和方法的特殊数据类型. 我们知道,数组是用来描述数据的.其实呢,对象也是用来描述数据的.只不过有一点点的区别,那就是数组的下标只能是数字.所以,数组最好只用来装同样意义的内容.比如说[1,2,3,4,5]或者["a","b","c","d","e"]等.因为他们的表达的含义是一样的.那么如何表达含义不