资讯专栏INFORMATION COLUMN

JS难点之hoist

biaoxiaoduan / 1417人阅读

摘要:但是变量只有其声明被提前在作用域的最开始处,赋值结果仍然还在原来位置。

这篇博文是之前在CSDN写的,现在移至sf。

有过C或者Java类编程经验的同学,对于“先声明后使用”的规则很熟悉,如果使用未声明的变量或者函数,编译时程序会报错!但是,JavaScript却是一个‘大奇葩’,可以在变量或者函数声明之前使用,现在根据我的理解在做一下说明。

首先说明JS的hoist分为变量hoist函数hoist两种。

一、变量hoist

看一段程序

       var a=10;  
       function fun(){  
         console.log(a);  
         var a=100;  
         console.log(a);  
      }  
       fun();//undefined   100  
       console.log(a);//10  

 

我们知道在js中,作用域分为全局作用域和函数作用域两种(ES6新特性,增加了块级作用域,另做说明)。全局变量声明有三种方式:

var(关键字)+变量名(标识符)方式在function外部声明,显示声明

没有使用var,直接给标识符赋值,隐式声明

使用window全局对象来声明,全局对象的属性也应是全局变量 eg:window.test=50; alert(test);

  

好,很显然,var a=10;在程序中是全局变量。那么,按照我们正常的逻辑输出结果为:10  100  10。但是,实际输出结果为:undefined 100  10,其实是JS解析器的解析原因,它会将当前作用域中声明的所有变量和函数,放在作用域的最开始处。但是变量只有其声明被提前在作用域的最开始处,赋值结果仍然还在原来位置。上述代码对于解析器来说,其实是:

       var a=10;  
       function fun(){
          var a;  
          console.log(a);  
          a=100;  
          console.log(a);  
       }  

       fun();//undefined   100  
       console.log(a);//10
二、函数hoist

 
讲完变量hoist,现在再讲一下函数hoist,函数hoist又分为两种情况。一种是函数声明,另一种是函数作为值赋值给变量

先说第一种情况:

   fun();//2  

   function fun(){console.log(2);} 

在这种情况下,可以看出,函数JS解释器允许在函数声明之前使用函数,其实也就说明,在这种情况,不仅函数名提前了,同时,函数体也被提前。所以可以上述代码可以执行。再说第二种情况:

     fun();  
     var fun=function(){  
        console.log(2);  
     }

结果为:Uncaught TypeError: fun is not a function  可以看出在此例中,函数只是变量声明声明提前,但是赋值没有提前,并且被提前的变量默认为undefined,所以报的错误类型为“typeerror”,因为undefined不是函数,不能被调用。

三、变量名和函数名相同时的hoist
       function fun(){console.log(1);}  
       fun();//2  
       function fun(){console.log(2);}  
       fun();//2  
       var fun=100;  
       console.log(fun);//100  
       fun();//报错

在此例中,函数名和变量名相同,都是fun,都会提前,那么在提前时,有什么需要注意的地方呢? 

函数声明比变量声明更置顶

声明过得变量不会重复声明

  

所以上述代码等效于:

    function fun(){console.log(1);}  
     function fun(){console.log(2);}//函数体覆盖上一层函数体  
     var fun;//实际无效  
     fun();  
     fun();  
     fun=100;  
     console.log(fun);  
     fun();

以上就是本人对于JS的hoist问题的理解,如果哪位同学,发现其中有误,欢迎指正!我的微信号为:Alfred-kai。 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101930.html

相关文章

  • webpack2 示例:Scope Hoisting 和 Code Splitting

    摘要:原文链接译者这个示例演示了与代码拆分相结合的。这是示例的依赖图实线表示同步导入,虚线表示异步导入除之外的所有模块都是模块。为了避免冲突,模块中的模块连接标识符被重命名,并简化了内部导入。根模块的外部导入和导出使用现有的结构。 原文链接:https://github.com/webpack/we...译者:@justjavac 这个示例演示了与代码拆分相结合的 Scope Hoistin...

    chunquedong 评论0 收藏0
  • 10个JavaScript难点

    摘要:每个构造函数都有一个属性,用于设置所有实例对象需要共享的属性和方法。凭直觉,函数重载可以通过或者实现,这就不去管它了。自从年双十一正式上线,累计处理了亿错误事件,得到了金山软件等众多知名用户的认可。 译者按:能够读懂这篇博客的JavaScript开发者,运气不会太差... 原文: 10 JavaScript concepts every Node.js programmer must ...

    anquan 评论0 收藏0
  • 10个JavaScript难点

    摘要:每个构造函数都有一个属性,用于设置所有实例对象需要共享的属性和方法。函数重载所谓函数重载,就是函数名称一样,但是输入输出不一样。凭直觉,函数重载可以通过或者实现,这就不去管它了。 10个JavaScript难点 1.立即执行函数 立即执行函数,即Immediately Invoked Function Expression (IIFE),正如它的名字,就是创建函数的同时立即执行。它没有...

    nidaye 评论0 收藏0
  • 【前端工程师手册】JavaScript作用域

    摘要:函数作用域和块作用域前面讲了是词法作用域,那么什么时候会创建作用域呢主要是基于函数级别的作用域,也就是每一个函数都会创建一个作用域。函数会被当作函数表达式而不是一个标准的函数声明来处理。 什么是作用域 来一段《你不知道的JavaScript-上卷》中的原话: 几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个 值进行访问或修改,这些变量住在哪里?换句话说,它...

    Paul_King 评论0 收藏0
  • 谈谈JavaScript的词法环境和闭包(一)

    摘要:换句话说,定义在闭包中的函数可以记忆它被创建时候的环境。词法环境的概念定义摘自百科。一个词法环境由一个环境记录项和可能为空的外部词法环境引用构成。中使用词法环境管理静态作用域。 一个资深的同事在我出发去面试前告诫我,问JS知识点的时候千万别主动提闭包,它就是一个坑啊!坑啊!啊! 闭包确实是js的难点和重点,其实也没那么可怕,关键是机制的理解,可以和函数一起单独拿出来说说,其实关于闭包的...

    AlphaWatch 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<