今天在群里吹水时,有群友提出一个问题。我一看很简单,就立马给出了答案:因为存在变量提升,所以输出undefined。本以为无人反驳,可确招来口诛笔伐。作为写实派的我,一贯以来坚持真实是我的使命,岂能容忍这等虚头巴脑的言论攻击。遂以此文记之,本在还原真实。奈何文笔拙劣,恐表述不当,误人子弟。若有不当之处,还请众佬及时斧正,以正视听。


就是下面这段代码:

var obj = {
say: function () { console.log(obj) }()
} // 输出 undefined

为什么是undefined?

这个问题看似简单,不值一提,可实际上是小孩没娘,说来话长!

尽管如此,我还是长话短说。很简单,因为在javascript执行之前,是存在一个“预编译”或者说是“预解析”这样的过程,在这个过程当中,进行了变量提升。

什么是变量提升?

变量提升就是将变量名提升到其所在作用域的顶部并赋值为undefined。与之相关的还有函数提升,不同的是,函数提升是将函数名及函数体全部提升到其所在作用域的顶部

与其说“预编译”,“预解析”可能更合理一点。为什么这样说?

因为在编程语言(如java,C#)当中,代码都是要先编译,后执行。而javascript作为脚本语言,不同于编程语言的一点是没有编译过程,但是它需要脚本解释器边解析边执行,而脚本解释器在解释执行代码前会先扫描一遍,这个过程就是“预解析”过程。

那么为什么会存在变量提升和函数提升呢?

在ES5当中,没有块级作用域的概念,只有全局作用域和函数作用域。声明变量可以用var关键字,也可以直接声明,只不过直接声明的变量是全局变量,而用var关键字声明的变量在全局作用域下就是全局变量,在函数体内就是局部变量。并且var关键字声明的变量在其所在的作用域下存在变量提升。

em... 那变量提升跟上面的代码输出的结果是undefined有什么关系呢? 好,请坐下,陈独秀同学。

我们来用代码还原一下真实过程:

预解析阶段:

生成全局对象,浏览器当中是window对象,node环境下是global对象

变量提升:

全局作用域下,变量obj提升到顶部,直接挂在window对象下,相当于window.obj = undefined;

say方法是一个匿名函数。匿名函数的函数体赋值给了变量say。所以变量say也会进行变量提升,它所在的作用域也是全局window下,相当于window.say = undefined;

函数提升:

function(){
console.log(obj); //obj = window.obj = undefined
}

执行阶段:

1,创建一个执行上下文(execution context),函数压栈,生成active object(活动对象)

1,执行/解释上下文中的function,为变量赋值

2,

参考:https://www.jianshu.com/p/edb2be5866eb

  • 需要记住的是:

    • 变量提升只提升变量名,函数提升会提升函数名及其函数体。
    • 变量提示优先级大于函数提升优先级。也就是说不管变量声明在前还是函数声明在前,都是先进行变量提升,再进行函数提升。

执行阶段:

function(){
console.log(obj); //输出undefined
}()

还原真实,javascript之预编译 / 预解析的更多相关文章

  1. Mybatis参数预编译

    Mybatis参数预编译 一.数据库预编译介绍 1.数据库SQL语句编译特性: 数据库接受到sql语句之后,需要词法和语义解析,优化sql语句,制定执行计划.这需要花费一些时间.但是很多情况,我们的一 ...

  2. mybatis深入理解之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

  3. mybatis之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

  4. mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译

    mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...

  5. .Net Core Razor 预编译,动态编译,混合编译

    预编译 预编译是ASP .Net Core的默认方式.在发布时,默认会将系统中的所有Razor视图进行预编译.编译好的视图DLL统一命名为 xxx.PrecompiledViews.dll 或者 xx ...

  6. 关于JavaScript预编译和执行顺序以及函数引用类型的思考

    昨晚在对项目中的一部分做模块化处理的时候,遇到了一个问题,一个重新定义的function对一个通用类中的function进行赋值覆盖的时候,失败了.问题抽象出来是这样的: <script > ...

  7. javascript的预编译和执行顺序

    原文:javascript的预编译和执行顺序 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题 代码: 代码一<html> ...

  8. JavaScript的预编译和执行

    JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和 ...

  9. javascript引擎执行的过程的理解--语法分析和预编译阶段

    一.概述 js是一种非常灵活的语言,理解js引擎的执行过程对于我们学习js是非常有必要的.看了很多这方便文章,大多数是讲的是事件循环(event loop)或者变量提升的等,并没有全面分析其中的过程. ...

随机推荐

  1. Toad for Oracle 创建表空间和用户

    表空间 1.找到Tablespace,右键,单击Create Tablespace 2.输入表空间名字,例如:test_tablespace3.单击"Date Files"选项卡, ...

  2. Python Flask Restful

    Flask  Restful 1.flask restful 在flask基础上进行一些封装,主要用于实现restful接口 2.restful的理解 1)URI(统一资源标识符):每一个URI代表一 ...

  3. mysql主从服务搭建

    一.安装mysql 检测当前centos是否安装了mysql:yum list installed | grep mysql yum list installed | grep mariadb    ...

  4. 64IE无法显示网页

    1.碰到如下图情况ie浏览器打开之后显示不了网页,但是试了下电脑上其他的浏览器都可以正常的打开网页. 2.解决办法为:打开浏览器-选择“工具”-“Internet选项”-“高级”-重置,重启浏览器后能 ...

  5. android上的bin/sbin/xbin等各种目录

    1. /system是用于存储 由AOSP构建生成的 不可变组件的 主要Android目录.这包括本机二进制文件,本机库,框架包和存储主要的应用程序.它通常是从根文件系统的单独映像中以只读方式挂载的, ...

  6. 使用STS创建springboot项目pom.xml文件报错org.apache.maven.archiver.MavenArchiver.getManifest

    首先我的STS版本时:3.7.3 解决办法:->help->Install New Software -> add->location ->输入: http://repo ...

  7. Python3.0科学计算学习之绘图(四)

    绘制三维图: mplot3d工具包提供了点.线.等值线.曲面和所有其他基本组件以及三维旋转缩放的三维绘图. 1.散点的三维数据图 from mpl_toolkits.mplot3d import ax ...

  8. 【备忘】mybatis的条件判断用<choose>

    mybatis并没有if..else,在mybatis的sql mapper文件中,条件判断要用choose..when..otherwise.   <choose> <when t ...

  9. Qt QDateEdit QDateTimeEdit

    展示一个效果,然后附上一个“笑话~~”...回想起来都是搞笑的. 笑话来了,,,,几个月前,为了做出时间选择界面,我亲自“创造”了一个...今天发现了QDateEdit的属性CalendarPopup ...

  10. js超链接锚点定位

    <html> <head> <meta charset="UTF-8"> </head> <body> <a on ...