zoukankan      html  css  js  c++  java
  • 立即执行函数

    原文:http://web.jobbole.com/82520/

    "立即执行函数"其实就是"立即执行函数表达式",这句话很重要,下面的文字就是描述为什么这么说。

    函数表达式
    
    var fn = funtion(){
        /* code */
    }
    
    函数声明
    
    function fn(){
      /* code */  
    }

    函数声明必须是一个单独的JavaScript语句。

    1.介绍函数(函数声明,函数表达式)

    在JavaScript中,每一个函数在被调用的时候都会创建一个执行上下文,在该函数内部定义的变量和函数只能在该函数内部使用,而正是因为这个上下文,让我们在调用函数的时候能创建一些私有变量。

    (图1)

    为什么函数one可以访问外部的i的值,可以参考:原文https://github.com/creeperyang/blog/issues/16

    简单描述一下,函数上下文:每调用一次产生一个上下文,调用完毕后销毁。

     

    在该上下文中,有个规律,里面的函数可以访问外部的函数的属性,而外部却不能访问函数的内部属性。在es6中就有块的概念了。

    为啥有这个规律?

    最小访问原则:

    不允许你代码中所有的东西在任意地方都可用的好处是什么?其中一个优势,是作用域为你的代码提供了一个安全层级。计算机安全中,有个常规的原则是:用户只能访问他们当前需要的东西。

    想想计算机管理员吧。他们在公司各个系统上拥有很多控制权,看起来甚至可以给予他们拥有全部权限的账号。假设你有一家公司,拥有三个管理员,他们都有系统的全部访问权限,并且一切运转正常。但是突然发生了一点意外,你的一个系统遭到恶意病毒攻击。现在你不知道这谁出的问题了吧?你这才意识到你应该只给他们基本用户的账号,并且只在需要时赋予他们完全的访问权。这能帮助你跟踪变化并记录每个人的操作。这叫做最小访问原则。眼熟吗?这个原则也应用于编程语言设计,在大多数编程语言(包括 JavaScript)中称为作用域。(引用http://web.jobbole.com/91134/)

    回到问题的核心。

    修改图(1)的代码.

    // makeCounter函数返回的是一个新的函数,该函数对makeCounter里的局部变量i享有使用权
    function makeCounter() {
      // i只是makeCounter函数内的局部变量
      var i = 0;
     
      return function() {
        console.log( ++i );
      };
    }
     
    // 注意counter和counter2是不同的实例,它们分别拥有自己范围里的i变量
     
    var counter = makeCounter();
    counter(); // 1
    counter(); // 2
     
    var counter2 = makeCounter();
    counter2(); // 1
    counter2(); // 2
     
    i; // 报错,i没有定义,它只是makeCounter内部的局部变量

    那么,立即执行函数其实就是加一个小括号,那么

    //列子1
    
    function (){
     /*code*/        
    }()
    
    //报错SyntaxError: Unexpected token (

    在JavaScript代码解释时,当遇到function关键词时,会默认把他当成一个函数声明,而不是函数表达式,如果没有把它显视地表达成函数表达式,就报错了,因为函数声明需要一个函数名,而上面的代码中函数没有函数名。(以上代码,也正是在执行到第一个左括号(时报错,因为(前理论上是应该有个函数名的。)

    加个函数名

    //列子2
    
    function foo(){
    /*code*/
    }()
    
    //依旧报错 SyntaxError: Unexpected token )

    为什么会这样?在一个表达式后面加上括号,表示该表达式立即执行;而如果是在一个语句后面加上括号,该括号完全和之前的语句不搭嘎,而只是一个分组操作符,用来控制运算中的优先级(小括号里的先运算)。

    如果没有优先级的话,这句话是对的,但是小括号的优先级比function的高,所以就会报错

    //修改之后的代码
    
    (function foo(){
     /*code*/
    }())

    为什么这样就能立即执行并且不报错呢?因为在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明

    还有一些其他的骚操作:

    // 这是一个自执行函数,函数内部执行的是自己,递归调用
    function foo() { foo(); }
     
    // 这是一个自执行匿名函数,因为它没有函数名
    // 所以如果要递归调用自己的话必须用arguments.callee
    var foo = function() { arguments.callee(); };
     
    // 这可能也算是个自执行匿名函数,但仅仅是foo标志引用它自身
    // 如果你将foo改变成其它的,你将得到一个used-to-self-execute匿名函数
    var foo = function() { foo(); };
     
    // 有些人叫它自执行匿名函数,尽管它没有执行自己,只是立即执行而已
    (function(){ /* code */ }());
     
    // 给函数表达式添加了标志名称,可以方便debug
    // 但是一旦添加了标志名称,这个函数就不再是匿名的了
    (function foo(){ /* code */ }());
     
    // 立即执行函数也可以自执行,不过不常用罢了
    (function(){ arguments.callee(); }());
    (function foo(){ foo(); }());
  • 相关阅读:
    Java中static、final、static final的区别(转)
    Google的JSON风格指南
    Google代码风格指南
    Java中的final关键字(转)
    Java的不定参数(eg:Object...)(转)
    Java Enum枚举的用法(转)
    Java中包装类型和基本类型的使用场景(什么时候使用包装类型)(转)
    Java常用的集合类(转)
    使用Swagger生成Spring Boot REST客户端(支持Feign)(待实践)
    Java搜索引擎选择: Elasticsearch与Solr(转)
  • 原文地址:https://www.cnblogs.com/damai/p/9008655.html
Copyright © 2011-2022 走看看