还原真实,javascript之预编译 / 预解析
今天在群里吹水时,有群友提出一个问题。我一看很简单,就立马给出了答案:因为存在变量提升,所以输出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之预编译 / 预解析的更多相关文章
- Mybatis参数预编译
Mybatis参数预编译 一.数据库预编译介绍 1.数据库SQL语句编译特性: 数据库接受到sql语句之后,需要词法和语义解析,优化sql语句,制定执行计划.这需要花费一些时间.但是很多情况,我们的一 ...
- mybatis深入理解之 # 与 $ 区别以及 sql 预编译
mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...
- mybatis之 # 与 $ 区别以及 sql 预编译
mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...
- mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译
mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...
- .Net Core Razor 预编译,动态编译,混合编译
预编译 预编译是ASP .Net Core的默认方式.在发布时,默认会将系统中的所有Razor视图进行预编译.编译好的视图DLL统一命名为 xxx.PrecompiledViews.dll 或者 xx ...
- 关于JavaScript预编译和执行顺序以及函数引用类型的思考
昨晚在对项目中的一部分做模块化处理的时候,遇到了一个问题,一个重新定义的function对一个通用类中的function进行赋值覆盖的时候,失败了.问题抽象出来是这样的: <script > ...
- javascript的预编译和执行顺序
原文:javascript的预编译和执行顺序 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题 代码: 代码一<html> ...
- JavaScript的预编译和执行
JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和 ...
- javascript引擎执行的过程的理解--语法分析和预编译阶段
一.概述 js是一种非常灵活的语言,理解js引擎的执行过程对于我们学习js是非常有必要的.看了很多这方便文章,大多数是讲的是事件循环(event loop)或者变量提升的等,并没有全面分析其中的过程. ...
随机推荐
- 操作系统与cpu
- linux基础命令--groupadd 创建新的群组
描述 groupadd命令用于创建一个新的群组. groupadd命令默认会根据命令行指定的值和系统下的/etc/login.defs文件定义的值去修改系统下的/etc/group和/etc/gsha ...
- 允许浏览器下载exe.config文件
进入系统目录 %windir%\System32\inetsrv\config\ 编辑IIS配置文件 applicationHost.config 找到如下行 <requestFiltering ...
- 查看虚拟机里的Centos7的IP
这里之所以是查看下IP ,是我们后面要建一个Centos远程工具Xshell 连接Centos的时候,需要IP地址,所以我们这里先 学会查看虚拟机里的Centos7的IP地址 首先我们登录操作系统 用 ...
- Python3学习之路~7.3 反射
python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,该四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删除成员. ...
- centos7.5 安装gaussian09和 gaussianview4
一.安装gaussian09 1. 解压安装包 $ mkdir Gaussian$ cd Gaussian$ tar xvf g09_linux.tar 2. 设置环境变量 #gaussian09 e ...
- JavaScript 当前URL取参返回字典
getParam : function(){ return (key, strURL = window.location.search) => new RegExp("(^|\\?|& ...
- c++ 程序崩溃生成Dump文件
#include "Windows.h"#include "DbgHelp.h" int GenerateMiniDump(PEXCEPTION_POINTER ...
- PHP 以最快的方式判断字符串是否以某给定字符串开始
好久没搞代码了,最近找工作,重操旧业,在整理以前写的框架的时候发现,之前的自动加载部分执行速度上还是有可优化空间的,就是如果类名是以 risen\ 开始的(我的框架中的类都在此命名空间下),那么可直接 ...
- 安装pip、numpy、sklearn
1)pip安装:https://pip.pypa.io/en/stable/installing/To install pip, securely download get-pip.py. [1]:c ...