zoukankan      html  css  js  c++  java
  • 《JavaScript设计模式与开发》笔记 4.闭包

    •  1.变量的作用域
    •  2.变量的生存周期
    •  3.闭包更多作用
      • 1.封装变量
      • 2.延续局部变量寿命
    •  4.闭包和面向对象设计
    •  5.闭包和内存管理

    1.变量的作用域

    var func = function(){
        var a = 1;
    }
    func();
    console.log(a); //输出undefined
    var a = 1;
    fun1 = function(){
        var b = 2;
        fun2 = function(){
            var c = 3;
            console.log(b);   //输出 2
            console.log(a);   //输出 1
        }
        fun2();
        console.log(c);   //输出undefined
    }
    fun1();

    2.变量的生存周期

    var func = function(){
        var a = 1;
        return function(){
            a++;
            console.log(a);
        }
    }
    var f = func();
    f();    // 输出1
    f();    // 输出2
    f();    // 输出3
    f();    // 输出4

    当退出函数后,局部变量a并没有消失,而是似乎一致在某个地方存活着。这是因为当执行var f = func();时,f返回了一个匿名函数的引用,它可以访问到func()被调用时产生的环境,而局部变量a一致处于这个环境里。既然局部变量所在的环境还能被外界,这个局部变量就有了不被销毁的理由。这里产生了一个闭包结构,局部变量的声明看起来被延续了。

    既然f返回了一个匿名的函数引用,那么下面的也符合闭包

    var func = (function(){
        var a = 1;
        return function(){
            a++;
            console.log(a);
        }
    })();
    f();    // 输出1
    f();    // 输出2
    f();    // 输出3
    f();    // 输出4

    再次变种为引用对象的方式

    var func = {
        a :0,
        call:function(){
            this.a++;
            console.log(this.a);
        }
    }
    func.call();   //输出1
    func.call();   //输出2
    func.call();   //输出3

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <script>
        var nodes = document.getElementsByTagName('div');
        for(var i =0;i<nodes.length;i++){
            nodes[i].onclick=function(){
                alert(i);
            }
        }
    </script>
    </body>
    </html>

    测试这段代码就会发现,无论点击哪个div,最后弹出的结构都是5,。这是因为div节点onclick事件是被异步出发的,当事件出发的时候,for循环早已结束,此时变量i的值已经是5,所以在div的onclick事件函数中顺着作用域链从内到外查找变量i时,查找到的值总是5。

    解决方法是在闭包作用的帮助下,把每次循环的i值都封装起来。(就是把每个点击事件都独立放在内存里面。)

    var nodes = document.getElementsByTagName('div');
        for(var i =0;i<nodes.length;i++){
            (function(i){
                nodes[i].onclick=function(){
                    alert(i);
                }
            })(i);
        }

    3.闭包更多作用

    1.封装变量

    闭包可以帮组我们封装私有变量”

    var mult = function(){
        var a = 1;
        for(var i =0;i <arguments.length;i++){
            a = a*arguments[i];
        }
        return a;
    }
    console.log(mult(1,2,5));

    mult函数接受一些number类型的函数,并返回这些参数的乘积。现在我们觉得对于这些那些参数来说,每次都进行计算是一种浪费,我们可以加入缓存机制来提高这个函数的性能。

    var cache={};
    var mult = function(){
        var args = Array.prototype.join.call(arguments,',');  //将参数对象变成一个字符串 args 1,2,3
        if(cache[args]){
            console.log('执行缓存');
            return cache[args];
        }
        var a = 1;
        for(var i=0;i<arguments.length;i++){
            a = a*arguments[i];
        }
        return cache[args] = a;
    }
    console.log(mult(1,2,3));   //进行计算
    console.log(mult(1,2,3));   //执行缓存,不用计算

    继续封装减少页面全局变量

    var mult = (function(){
        var cache={};       //私有变量
        return function(){
            var args = Array.prototype.join.call(arguments,',');
            if(cache[args]){
                return cache[args];
            }
            var a = 1;
            for(var i=0;i<arguments.length;i++){
                a = a*arguments[i];
            }
            return cache[args] = a;
        }
    })()
    console.log(mult(1,2,3));   //进行计算
    console.log(mult(1,2,3));   //执行缓存,不用计算

    提炼代码,独立模块

    var mult = (function(){
        var cache={};       //私有变量
        var cala = function(){  
            var a = 1;
            for(var i=0;i<arguments.length;i++){
                a = a*arguments[i];
            }
            return a;
        }
        return function(){
            var args = Array.prototype.join.call(arguments,',');
            if(cache[args]){
                return cache[args];
            }
            return cache[args] = cala.apply(null,arguments);
        }
    })();
    console.log(mult(1,2,3));   //进行计算
    console.log(mult(1,2,3));   //执行缓存,不用计算
    2.延续局部变量的寿命
    var report = function(src){
        var img = new Image();
        img.src = src;
    }

    利用闭包来延续img的使用

    var report = (function(){
        var imgs = [];   //img就留在了内存里面
        return function(src){
            var img = new Image();
            imgs.push(img);
            img.src = src;
        }
    })();

    4.闭包和面向对象

    闭包:

    var extent = function(){
        var value =0;
        return {
            call:function(){
                value++;
                console.log(value);
            }
        }
    }
    var extent = extent();
    extent.call();   //输出1
    extent.call();   //输出2
    extent.call();   //输出3

    如果换成面向对象的写法就是

    var extent = {
        value :0,
        call:function(){
            this.value++;
            console.log(this.value);
        }
    }
    extent.call();   //输出1
    extent.call();   //输出2
    extent.call();   //输出3

    5.闭包和内存管理

    闭包是一个非常强大的特性,但人民对其他诸多误解,一种耸人听闻的说法就是闭包会造成内存泄漏。如果在将来需要回收这些变量,我们可以手动吧这些变量设置为null。

  • 相关阅读:
    pxc5.7配置安装
    在SQL中 给字符串补0方法
    python中字符串连接的四种方式
    python中math模块常用的方法整理
    python 字符串比较
    sql去重;同一条数据出现多条取一条的sql语句
    给一行添加数据库不存在的自然数顺序编号
    jvisualvm下载
    sql截取字符串后面四位
    idea破解更新
  • 原文地址:https://www.cnblogs.com/subtract/p/7139864.html
Copyright © 2011-2022 走看看