zoukankan      html  css  js  c++  java
  • js 立即调用的函数表达式

    当你声明类似function foo(){}或var foo = function(){}函数的时候,通过在后面加个括弧就可以实现自执行,例如foo(),看代码:

    // 因为想下面第一个声明的function可以在后面加一个括弧()就可以自己执行了,比如foo(),
    // 因为foo仅仅是function() { /* code */ }这个表达式的一个引用
     
    var foo = function(){ return 1; }();//foo=1;
     
    // 是不是意味着后面加个括弧都可以自动执行?
     
    function(){  return 1; }(); // SyntaxError: Unexpected token

    第2个代码会出错,因为在解析器解析全局的function或者function内部function关键字的时候,默认是认为function声明,而不是function表达式,如果你不显示告诉编译器,它默认会声明成一个缺少名字的function,并且抛出一个语法错误信息,因为function声明需要一个名字。

    有趣的是,即便你为上面那个错误的代码加上一个名字,他也会提示语法错误,只不过和上面的原因不一样。在一个表达式后面加上括号(),该表达式会立即执行但是在一个语句后面加上括号(),是完全不一样的意思,他的只是分组操作符

    // 下面这个function在语法上是没问题的,但是依然只是一个语句
    // 加上括号()以后依然会报错,因为分组操作符需要包含表达式
     
    function foo(){return 1; }(); // SyntaxError: Unexpected token )
     
    // 但是如果你在括弧()里传入一个表达式,将不会有异常抛出
    // 但是foo函数依然不会执行
    function foo(){ return 1; }( 1 );
     
    // 因为它完全等价于下面这个代码,一个function声明后面,又声明了一个毫无关系的表达式: 
    function foo(){ return 1; }
     
    ( 1 );

    要解决上述问题,非常简单,我们只需要用大括弧将代码的代码全部括住就行了,因为JavaScript里括弧()里面不能包含语句,所以在这一点上,解析器在解析function关键字的时候,会将相应的代码解析成function表达式,而不是function声明。

    // 下面2个括弧()都会立即执行
    
    (function () { /* code */ } ()); // 推荐使用这个
    (function () { /* code */ })(); // 但是这个也是可以用的
    
    // 由于括弧()和JS的&&,异或,逗号等操作符是在函数表达式和函数声明上消除歧义的
    // 所以一旦解析器知道其中一个已经是表达式了,其它的也都默认为表达式了
    
    var i = function () { return 10; } ();
    true && function () { /* code */ } ();
    0, function () { /* code */ } ();
    
    // 还有一个情况,使用new关键字,也可以用
    
    new function () { /* code */ }
    new function () { /* code */ } () // 如果需要传递参数,只需要加上括弧()

    和普通function执行的时候传参数一样,自执行的函数表达式也可以这么传参,因为闭包直接可以引用传入的这些参数,利用这些被lock住的传入参数,自执行函数表达式可以有效地保存状态。

    // 这个代码是错误的,因为变量i从来就没背locked住
    // 相反,当循环执行以后,我们在点击的时候i才获得数值
    // 因为这个时候i操真正获得值
    // 所以说无论点击那个连接,最终显示的都是I am link #10(如果有10个a元素的话)
    
    var elems = document.getElementsByTagName('a');
    
    for (var i = 0; i < elems.length; i++) {
    
        elems[i].addEventListener('click', function (e) {
            e.preventDefault();
            alert('I am link #' + i);
        }, 'false');
    
    }
    
    // 这个是可以用的,因为他在自执行函数表达式闭包内部
    // i的值作为locked的索引存在,在循环执行结束以后,尽管最后i的值变成了a元素总数(例如10)
    // 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了
    // 所以当点击连接的时候,结果是正确的
    
    var elems = document.getElementsByTagName('a');
    
    for (var i = 0; i < elems.length; i++) {
    
        (function (lockedInIndex) {
    
            elems[i].addEventListener('click', function (e) {
                e.preventDefault();
                alert('I am link #' + lockedInIndex);
            }, 'false');
    
        })(i);
    
    }
    
    // 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式
    // 而不是在addEventListener外部
    // 但是相对来说,上面的代码更具可读性
    
    var elems = document.getElementsByTagName('a');
    
    for (var i = 0; i < elems.length; i++) {
    
        elems[i].addEventListener('click', (function (lockedInIndex) {
            return function (e) {
                e.preventDefault();
                alert('I am link #' + lockedInIndex);
            };
        })(i), 'false');
    
    }

    参考:http://www.cnblogs.com/TomXu/archive/2011/12/31/2289423.html

  • 相关阅读:
    iOS最笨的办法实现无限轮播图(网络加载)
    iOS 动画基础总结篇
    ios 深入讲解iOS键盘一:控制键盘隐藏显示
    iOS开发之提交App中断出现:Cannot proceed with delivery: an existing transporter instance is currently uploading this package
    ios -仿微信有多级网页时,显示返回跟关闭按钮
    IOS启动页动画(uiview 淡入淡出效果 )2
    数量加减
    Swift泛型协议的N种用法
    一个swift版简单的用户名和密码输入textField
    Mac电脑上怎么设置环境变量
  • 原文地址:https://www.cnblogs.com/dehuachenyunfei/p/6582741.html
Copyright © 2011-2022 走看看