zoukankan      html  css  js  c++  java
  • 函数声明与函数表达式、变量提升

    函数的声明方式

    在定义一个函数的时候通常有两种声明方式:

    foo(){};     // 函数声明
    var foo = function(){};    // 函数表达式

    不同之处

    1. 函数表达式后面加括号可以直接执行
    2. 函数声明会提前预解析

    预解析

    让我们先看一个例子:

    foo();         //  函数声明
    foo_later();     //  foo_later is not a function
    
    function foo(){ console.log('函数声明'); }
    var foo_later = function(){ console.log('函数表达式'); }

    可以看到,函数声明foo被预解析了,它可以在其自身代码之前执行;而函数表达式foo_later则不能。要解决这个问题,我们先要弄清楚JavaScript解析器的工作机制。

    变量提升(hoist)

    JavaScript解析器会在自身作用域内将变量和函数声明提前(hoist),也就是说,上面的例子其实被解析器理解解析成了以下形式:

    function foo(){ console.log('函数声明'); }    // 函数声明全部被提前
    var foo_later;     // 函数表达式(变量声明)仅将变量提前,赋值操作没有被提前
    
    foo();             
    foo_later();     
    
    
    foo_later = function(){ console.log('函数表达式'); }

    这样也就可以解释,为什么在函数表达式之前调用函数,会返回错误了,因为它还没有被赋值,只是一个未定义变量,当然无法被执行。

    同样的,我们也可以试着猜测下面这段代码的输出结果:

    console.log(declaredLater);   
    
    var declaredLater = "Now it's defined!";
    
    console.log(declaredLater);    

    该段代码可以被解析成一下形式:

    var declaredLater;          
    
    console.log(declaredLater);    // undefined
    
    declaredLater = "Now it's defined!";
    
    console.log(declaredLater);    // Now it's defined!

    变量声明被提到最前(所以不会报出变量不存在的错误),但赋值没有被提前,所以第一次的输出结果是undefined。

    需要注意的是

    由于函数声明会被预解析,所以不要使用此种方法来声明不同函数。尝试猜想下面例子的输出结果:

    if(true){
      function aaa(){
        alert('1');
      }  
    }
    else{
      function aaa(){
        alert('2');
      }
    }
    
    aaa();

    与我们预想的不同,该段代码弹出的是“2”.这是因为两个函数声明在if语句被执行之前就被预解析了,所以if语句根本没有用,调用aaa()的时候直接执行了下面的函数。

    总结

    通过上面的讲解可以总结如下:

    • 变量的声明被提前到作用域顶部,赋值保留在原地
    • 函数声明整个“被提前”
    • 函数作为值赋给变量时只有变量“被提前”了,函数没有“被提前”

    通过练习上面的实例自己多感受一下。另外,作为最佳实践:变量声明一定要放在作用域/函数的最上方(JavaScript 只有函数作用域!)。

     

    参考:

    JavaScript 中对变量和函数声明的“提前(hoist)”

    函数声明 VS 函数表达式

  • 相关阅读:
    java Activiti 工作流引擎 SSM 框架模块设计方案
    自定义表单 Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    数据库设计的十个最佳实践
    activiti 汉化 stencilset.json 文件内容
    JAVA oa 办公系统模块 设计方案
    java 考试系统 在线学习 视频直播 人脸识别 springboot框架 前后分离 PC和手机端
    集成 nacos注册中心配置使用
    “感恩节 ”怼记
    仓颉编程语言的一点期望
    关于System.out.println()与System.out.print("\n")的区别
  • 原文地址:https://www.cnblogs.com/timl525/p/5092132.html
Copyright © 2011-2022 走看看