• JavaScript 闭包系列二(匿名函数及函数的闭包)


    一. 匿名函数

    1. 函数的定义,可分为三种

    1) 函数声明方式

    function double(x) {
        return 2*x;
    }

    2)Function构造函数,把参数列表和函数体都作为字符串,不方便,不建议使用

    var double = new Function('x', 'return 2*x;');

    3)函数表达式方式

    var double = function(x) {
        return 2*x;
    }

    该形式中,等号右边是一个匿名函数,创建函数完毕后,将该函数赋给了变量double。

    2. 匿名函数

    1)第一种方式

    var double= function(x) {
        return 2*x;
    }

    等号右边是一个匿名函数。注意匿名函数不能直接独立的房子代码中,如下代码

    functino(x) {
        return 2*x;
    }                  //SyntaxError: Unexpected token (

    2)第二种方式

    (function(x,y) {
        console.log(x+y);
    })(2,3);

    创建一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数并传入参数。

    二. 闭包(Closure)

    闭包的含义:外层函数包含内层函数,内层函数可以访问外层函数的所有变量,即使外层函数执行完毕。(JavaScript作用域链)

    题外话:上述对于闭包的解释与《JavaScript 闭包系列一》中不完全吻合。 上述解释,闭包成立只需满足:函数inner嵌套在函数outer内部。另一些文章对于闭包的解释,闭包成立需要两个条件:1)函数inner嵌套在函数outer内部;2)函数outer返回函数inner。对此,我已经凌乱了,各路大侠谁能够给个定论

    Example 1:

    函数outer是瞬间执行的(约0.00001毫秒),在函数outer体内创建了一个变量str,在outer执行完毕后,str变量未被释放,这是由于setTimeout内的匿名函数存在对变量str的引用。等到2秒后,匿名函数执行完毕,str才被释放。

    function outer() {
        var str = "closure";
        setTimeout(function() {
            console.log(str);
        }, 2000);
    }
    outer();  //closure

    Example 2:此例是否为闭包呢?

    function outer() {
        var i = 22;
        (function inner() {
            console.log(i);
        })();
    }
    outer();  //22

    Example 3:简化代码

    function forTimeout(x, y) {
        console.log(x + y);
    }
    function delay(x, y, time) {
        setTimeout('forTimeout(' + x + ',' + y + ')', time);
    }
    //简化后
    function delay(x, y, time) {
        setTimeout(
            function() {
                forTimeout(x,y);
            }
        ,time);
    }
    delay(3, 4, 2000); //7


    三. 匿名函数与闭包

    匿名函数的最大用途是创建闭包,它也可用来构建命名空间,减少全局变量的使用。

    Example1:

    匿名函数中的addEvent和removeEvent为局部变量,但是可以通过全局变量oEvent使用它,大大减少了全局变量的使用,增强了网页的安全性。

    var oEvent = {};
    (function() {
        var addEvent = function() {};
        function removeEvent(){}

        oEvent.addEvent = addEvent;
        oEvent.removeEvent = removeEvent;
    })();

    Example2:

    创建一个变量sun_mile_rain,并通过直接调用匿名函数初始化为5,这种小技巧有时十分有用。

    var sun_mile_rain = (function(x , y){
        return x + y;
    })(2 , 3);
    console.log(sun_mile_rain);  //5
    //
    也可使用如下的方式,第一个括号只是帮助我们阅读,但是不推荐下面这种书写格式
    var sun_mile_rain = function(x , y){
        return x + y;
    }(2 , 3);

    Example3:

    代码中,变量one定义在函数内部,是一个局部变量,因此外部是不可以访问的。但inner函数可以访问变量one,又将全局变量outer引用了inner,因此执行outer()能访问到one的值。

    var outer = null;
    (function() {
        var one = 1;
        function inner() {
            one += 1;
            console.log(one);
        }
        outer = inner;
    })();
    outer();  //2
    outer();  //3
    outer();  //4

    换一种形式:函数fn执行,返回inner,将fn的执行结果赋给全局变量outer。执行outer也能访问到one的值。因此可得知闭包的形式可以有多种。

    function fn() {
        var one = 1;
        function inner() {
            one += 1;
            console.log(one);
        }
        return inner;
    }
    var outer = fn();
    outer();  //2
    outer();  //3
    outer();  //4


    四. 闭包与变量

    闭包允许内层函数引用父函数中的变量,但该变量是最终值

    鼠标移过每一个li元素时,控制台输出的值都是3,而不是我们期望的元素下标。当mouseover事件调用监听函数时,首先在匿名函数内部查找i是否定义,结果没找到,因此向上查找,在全局环境中找到i,并且i的值是3(循环后的值)。因此每次输出的都是3。 

    /*
    <ul>
        <li>one</li>
        <li>two</li>
        <li>three</li>
    </ul>
    */
    var lists = document.getElementsByTagName("li");
    for(var i=0; i<lists.length; i++) {
        lists[i].onmouseover = function() {
            console.log(i);
        }
    }

    注意:此处的闭包,并不是函数嵌套函数的形式,而是匿名函数包含在全局环境中的形式。

    针对上述代码,有三种方法改进,使得鼠标移动到li元素上时,控制台输出对应的下标值。

    1)立即执行的匿名函数

    var lists = document.getElementsByTagName("li");
    for (var i = 0; i < lists.length; i++) {
        (function(index) {
            lists[i].onmouseover = function() {
                console.log(index);
            };
        })(i);
    }

     2)在DOM元素上绑定$$index属性记录下标

    var lists = document.getElementsByTagName("li");
    for (var i = 0; i < lists.length; i++) {
        lists[i].$$index = i;
        lists[i].onmouseover = function() {
            console.log(this.$$index);
        };
    }

    3)

    var lists = document.getElementsByTagName("li");
    for (var i = 0; i < lists.length; i++) {
        eventListener(lists[i],i);
    }
    function eventListener(list,index) {
        list.onmouseover = function() {
            console.log(index);
        }
    }

    时间:2014-10-23

    地点:合肥

    引用:http://www.cnblogs.com/rainman/archive/2009/05/04/1448899.html

  • 相关阅读:
    21.错误和异常
    20.装饰器相关
    19.装饰器
    18.函数编程的练习
    Remove Duplicates from Sorted List II
    Ubuntu 12.04输入密码登陆后又跳回到登录界面
    Remove Linked List Elements
    Populating Next Right Pointers in Each Node *
    Convert Sorted Array to Binary Search Tree
    Flatten Binary Tree to Linked List *
  • 原文地址:https://www.cnblogs.com/sun-mile-rain/p/4045371.html
Copyright © 2020-2023  润新知