zoukankan      html  css  js  c++  java
  • JS基础学习——闭包

    JS基础学习——闭包

    什么是闭包

    闭包的定义如下,它的意思是闭包使得函数可以记住和访问它的词法范围,即使函数是在它声明的词法范围外执行。更简单来讲,函数为了自己能够正确执行,它对自己的词法范围产生闭包,在它执行完毕释放之前,它会阻止相关的词法范围提早关闭释放。

    Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.

    一个比较简单的例子就是嵌套查询,如code 1所示,因为bar函数需要访问foo函数内的变量a,因此bar对foo的内部范围产生了闭包,但在这个例子中bar函数是在其声明时的词法范围内执行的,因此闭包现象不能很好体现,但是需要知道在这种嵌套函数中闭包也是存在的。

    /*-----------code 1----------*/
    function foo() {
    var a = 2;
    function bar() {
    console.log( a ); // 2
    }
    bar();
    }
    foo();
    

    code 2中闭包现象比较明显,按照函数作用域的理解,函数内部的变量在函数运行结束之后就应该消亡,但由于bar对foo的内部范围产生了闭包,使得bar在foo执行完毕之后还能继续访问foo的内部变量,具体来说,由于bar有对foo内部变量存在引用,因此在bar作为返回值被传递出去时对foo产生了闭包,这使得foo内部的变量继续存在,bar在词法范围外部执行时也能根据自己定义时的词法范围成功找到了a变量。需要注意,由于闭包占用内存空间,所以要谨慎使用闭包。尽量在使用完闭包后,及时解除引用,以便更早释放内存,如code 2中最后一句所示。

    /*-----------code 2----------*/
    function foo() {
    var a = 2;
    function bar() {
    console.log( a );
    }
    return bar;
    }
    var baz = foo();
    baz(); // 2 -- Whoa, closure was just observed, man.
    baz = null;
    

    循环闭包中的经典例子

    code 3设计之初是希望arr中存放的2个方法的运行结果分别是0和1,但是由于两个function都对同一个变量i具有闭包,而变量i在循环的过程中发生了改变,因此最终运行结果不是希望的那样,两个方法都将返回2。

    想要实现原先的设计目标,有两种方法可以实现,第一种是使用IIFE创建函数作用域,如code 4所示,第二种方法是使用let关键词,如code 5所示,let声明的循环变量绑定的是单次迭代作用域,每次迭代都会产生一个新的同名循环变量,具体看JS基础学习——作用域

    /*-----------code 3----------*/
    function foo(){
        var arr = [];
        for(var i = 0; i < 2; i++){
            arr[i] = function(){
                return i;
            }
        }
        return arr;
    }
    var bar = foo();
    console.log(bar[0]());//2
    
    /*-----------code 4----------*/
    function foo(){
        var arr = [];
        for(var i = 0; i < 2; i++){
            arr[i] = (function fn(j){
                return function test(){
                    return j;
                }
            })(i);
        }
        return arr;
    }
    var bar = foo();
    console.log(bar[0]());//0
    
    /*-----------code 5----------*/
    function foo(){
        var arr = [];
        for(let i = 0; i < 2; i++){
            arr[i] = function(){
                return i;
            }
        }
        return arr;
    }
    var bar = foo();
    console.log(bar[0]());//0
    

    模块中的闭包

    一个函数,它以对象为返回值,且对象中至少包含一个属性为内部函数,且该内部函数访问函数的私有变量(蕴含闭包),那么这个函数就是一个模块,有点类似于c++、java中的类概念。code 6就是一个模块函数。

    /*-----------code 6----------*/
    var foo = (function CoolModule() {
    var something = "cool";
    var another = [1, 2, 3];
    function doSomething() {
    	console.log( something );
    }
    function doAnother() {
    	console.log( another.join( " ! " ) );
    }
    return {
    	doSomething: doSomething,
    	doAnother: doAnother
    };
    })();
    foo.doSomething(); // cool
    foo.doAnother(); // 1 ! 2 ! 3
    

    参考资料:

    [1] You don't know js -- Scope & Closures

    [2] 深入理解闭包系列第四篇——常见的一个循环和闭包的错误详解

  • 相关阅读:
    SQL Server 2005高级程序设计
    SQL语言艺术
    无益的程序
    Django Ajax动态图形监控
    C/C++ Qt 基本文件读写方法
    Django 实现统计网站访问状态
    Python 实现 WebSocket 通信
    Django Admin后台定制简单监控页
    Django Ajax 实现Web命令行执行
    C/C++ Qt QThread 线程组件应用
  • 原文地址:https://www.cnblogs.com/ammyben/p/8445656.html
Copyright © 2011-2022 走看看