美文网首页
函数与作用域

函数与作用域

作者: akena | 来源:发表于2017-12-17 22:59 被阅读0次
    函数声明和函数表达式
    • 函数声明
      function fn() {}
      
      • 必须有函数名
      • 函数可以在任意地方调用
    • 函数表达式
      var fn = function fn() {}
      
      • function 后函数名可以省略
      • function 后函数名只能在函数内部使用
      • 函数表达式只能在声明之后才能调用
    作用域和声明提升
    • 作用域

      • 变量作用域
        • 全局变量拥有全局作用域,局部变量只在函数体内有定义
        • 函数体内,局部变量优先级高于同名的全局变量
      • 函数作用域
        • 块级作用域 概念类似的,JavaScript 使用函数作用域(function scope),即在函数体内声明的所有变量在函数体内可以使用及复用
    • 声明提升

      在代码开始执行之前,解析器会在初始化进程中创建全局变量对象 VO(variable object)VO 中包含全局对象原有属性,全局定义的变量和函数

      • VO 的变化与上下文代码的两个执行阶段有关
        1. 变量初始化,进入执行上下文
        2. 执行代码
      • 在变量初始化阶段,VO 会被以下属性按优先级顺序填充
        1. 函数参数(未传入实参时,初始值为 undefined
        2. 函数声明(存在相同名称的属性时,会完全替换该属性)
        3. 变量声明(初始值为 undefined,存在相同名称的属性时会忽略该声明)
      • 在执行代码阶段,依据以上流程,可得知 JavaScript 声明提升(declaration hoisting)特性的结果,即:
        • 将 JavaScript 函数声明的所有变量添加到执行环境中,并将它们按优先级顺序放到源代码树的顶部,故函数声明提升在变量声明提升之前
          var haha = function() {
            console.log('赋值给变量haha')
          }
        
          function haha() {
            console.log('具名函数haha')
          }
        
          haha();  //赋值给变量haha
        
    arguments 对象
    • arguments 对象是所有函数中都可用的局部变量,此对象包含传递给函数的每个参数的条目,示例:
        arguments[0]   //对应第一个参数的条目
        arguments[1]   //类推,第二个
        arguments[2]
      
        arguments[1] = 'new Value';  //参数可被设置
      
    • arguments 对象类似 Array,但不是 Array,除了 length 属性来确定传递参数个数外没有任何 Array 属性
    函数的重载
    • Java 和 JavaScript 的对比
      • Java 中,通过方法签名来唯一确定一个方法。方法签名的要素包括:方法名、参数类型、参数顺序和参数个数。若两个方法名称相同,但其他要素不同,编译器便将其视为同名的不同方法,从而导致了重载现象
      • JavaScript 中,函数没有签名,其参数由包含零或多个值的数组来表示,完全靠函数名称唯一确定。当存在相同名称的函数时,则后者会覆盖前者,因而不存在重载
    • JavaScript 模仿函数的重载
        //通过检查传入函数中参数的数量,间接达到重载的目的
        function add(num1, num2) {
          if(arguments.length == 1) {
            console.log(arguments[0] + "input 2nd parameter")
          }
          if(arguments.length == 2) {
            console.log(arguments[0] + arguments[1])
          }
        }
      
    立即执行函数表达式 IIFE

    IIFE 即声明一个匿名函数并即时调用

    • 两种模式
      • 当圆括号包裹函数时,它会默认将函数作为表达式去解析,而不是函数声明
        (function() { /* code */}());
        
      • 当圆括号出现在匿名函数的末尾想要调用函数时,它会默认将函数当成是函数声明
        (function() { /* code */})();
        
    • 用途
      • 创建一个独立的作用域,避免全局污染
     // 这是一个自执行函数,函数内部执行的是自己,递归调用
     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(); }());
    
    递归求n!
    function fn(i) {
      if(i < 2) {
        return 1
      }else {
        return i*fn(i-1)
      }
    }
    
    //简写
    function fn(i) {
      return i<2?1:i*fn(i-1)
    }
    

    refer to 变量对象 | cnblogs立即执行函数表达式(IIFE) | segmentfault立即执行函数 | 每日一题

    相关文章

      网友评论

          本文标题:函数与作用域

          本文链接:https://www.haomeiwen.com/subject/svzuwxtx.html