zoukankan      html  css  js  c++  java
  • 一步步学习javascript基础篇(6):函数表达式之【闭包】

    回顾前面介绍过的三种定义函数方式

    1. function sum (num1, num2) { return num1 + num2; }  //函数声明语法定义

    2. var sum = function(num1, num2){ return num1 + num2; }; //函数表达式定义 

    3. var sum = new Function("num1", "num2", "return num1 + num2"); //Function 构造函数 

    在分析闭包之前我们先来看看,定义和调用函数容易犯的错误。

    例1:

    sayHi(); //错误:函数还不存在
    var sayHi = function () {
        alert("test");
    };

    例2:

    if (true) {
        function sayHi() {
            alert("1");
        }
    } else {
        function sayHi() {
            alert("2");
        }
    }
    sayHi();//打印结果并不是我们想要的

    例3:

    var fun1 = function fun2() {
        alert("test");
    }
    fun2();//错误:函数还不存在

    在例1中,我们不能在使用函数声明式语法定义之前调用函数。解决方案:

    1.如果使用函数表达式定义函数的话,需要在表达式定义后调用。

    var sayHi = function () {
        alert("test");
    };
    sayHi()

    2.使用函数声明式。(这里浏览器引擎会函数声明提升,在所有代码执行之前先读取函数声明)

    sayHi(); 
    function sayHi () {
        alert("test");
    };

    在例2中,我们预期的结果应该是打印1,实际结果是打印2。

    为什么会这样?正因为函数声明提升,所以浏览器在预解析的时候不会判断if条件,直接解析第二个函数定义的时候覆盖了第一个。

    解决方案:

    在例3中,发现只能只用fun1()调用,而不能使用fun2()调用。

    我自己的理解,真正原因不知道。没找到资料。 

    因为1: function fun3() { }; 等效与 var fun3 = function fun3() { }; 如图:

    所以只能只用fun1()调用,而不能使用fun2()调用。

    其实这里我还是有疑问的?哪位大神知道,望告知。

    既然,fun2在外面不能调用为什么在函数内部能调用?虽然在debugger还是得不到fun1。

    好了,通过上面的三道题目热身。我们继续今天的主题“闭包”。

    1.什么是闭包?

    定义:就是有权访问另一个函数作用域的变量的函数

    我们先从一个示例函数开始:

    例1:

    function fun() {
        var a = "张三";
    }
    fun();//在我们执行完后,变量a就被标记为销毁了

    例2:

    function fun() {
        var a = "张三";
        return function () {
            alert("test");
        }
    }
    var f = fun();//同样,在我们执行完后,变量a就被标记为销毁了

    例3:

    function fun() {
        var a = "张三";
        return function () {
            alert(a);
        }
    }
    var f = fun();//【现在情况发生变化了,如果a被销毁,显然f被调用的话就不能访问到变量a的值了】
    f();//【然后变量a的值正常的被访问到了】
    //这就是闭包,当函数A 返回的函数B 里面使用到了函数A的变量,那么函数B就使用了闭包。

    示例:

    显然,滥用闭包会增大内存的使用。所以非特殊情况尽量不要使用闭包。如果用到了,记得手动设置空引用,内存才能被回收 f = null; 

    图解:(不了解作用域链的同学请先看前面的文章作用域和作用域链

    补充:例4:(闭包的实例应用)

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <style type="text/css">
            .tempBut {
                display: none;
            }
        </style>
    </head>
    <body>
        <div class="mydiv">
            <input value="but" type="button" class="tempBut" />
        </div>
        <script src="Scripts/jquery-1.8.2.js"></script>
        <script type="text/javascript">
          
            for (var i = 0; i < 10; i++) {
                var tempHtml = $(".tempBut").clone().removeClass("tempBut"); 
                //tempHtml.click(function (i) {
                //    alert(i);//怎样打印 0 到 9
                //});
                (function (num) {//使用闭包传值
                    tempHtml.click(function () {
                        alert(num);
                    });
                })(i);
                $(".mydiv").append(tempHtml);
            }
        </script>
    </body>
    </html>

    2.什么是匿名函数?(仅仅只是解释这个概念)

    如:(即,没有名字的函数)

     

    关于对象中函数的返回值是匿名函数时,this的怪异现象 

    讲解之前,先清醒下头脑,不要越看越迷糊了。如果迷糊了,那就直接忽略下面的。

    var name1 = "张三";
    var obj = {
        name1: "李四",            
        fun2: function () {
            alert(this.name1);
        },
        fun3: function () {
            return function () {
                alert(this.name1);
            }
        }
    }
    obj.fun2();//打印结果"李四"意料之中的。
    obj.fun3()();//因为这里返回的是一个函数,所以要再加一对()来调用。打印结果是"张三",意料之外。
    //真是百事不得其解啊,什么this指向了全局?

    我们前面讲过“哪个对象点出来的方法,this就是哪个对象”,那我们的 obj.fun3()() 打印的是“张三”也就是说this执行了全局作用域。

    我们看看下面的示例也许就知道为什么了。

    var name1 = "张三";
    var obj = {
        name1: "李四",            
        fun2: function () {
            alert(this.name1);
        },
        fun3: function () {
            return function () {
                alert(this.name1);
            }
        }
    }       
    //obj.fun3()();
    var obj2 = {};
    obj2.name1 = "test";
    obj2.fun = obj.fun3();
    obj2.fun();//打印结果"test",再次证明了“哪个对象点出来的方法,this就是哪个对象”.

    我们来分解下 obj.fun3()() 先是 obj.fun3() 返回一个匿名函数到了window作用域,然后接着调用this就指向了window了。(感觉解释有点勉强,也不知道对不,暂时自己先是这么理解的) 

    这是学习记录,不是教程。文中错误难免,您可以指出错误,但请不要言辞刻薄。

    原文链接:http://haojima.net/zhaopei/519.html

    本文已同步至目录索引:一步步学习javascript

    欢迎对个人博客感兴趣的道友加入群:【嗨-博客】469075305 入群须知

  • 相关阅读:
    【转】彻底解决matplotlib中文乱码问题
    angularjs依赖注入,setInterval()功能
    【转】图解SQL的各种连接join
    关于c#调用matlab时,deploytool选项没有.NET Assembly的问题的解决
    SQL从其他服务器数据库导入数据到本地数据库中
    【转】Asp.net下载文件、文件流输出 直接输出文件
    【转】正则应用实例,如将多个空格改为1个空格
    【转】线程间操作无效:从不是创建控件 的线程访问它,解决办法
    js获取鼠标坐标,设置div的高度、位置、内容等,及注意要点
    Java线程阻塞的方法
  • 原文地址:https://www.cnblogs.com/zhaopei/p/js_closure.html
Copyright © 2011-2022 走看看