问题:有如下代码

 var a = 1;
function pop() {
alert(a);
var a = 5;
}
pop();//执行结果,弹出undefined

这段代码的执行结果为undefined,为什么呢?

JS的解析与执行并不是读一行,处理一行,读一行,处理一行这样进行的,而是分为两个阶段:

1、预处理阶段;

2、执行阶段;

然后分别以全局和函数内部的局部代码而言:

1、全局预处理

在解析JS代码的时候,首先会创建一个全局LexicalEnviroment{ }(词法环境)对象

接下来扫描JS代码里面的两个部分:

a、用声明的方式创建的函数;

b、用var定义的变量;

扫面完毕后将这些变量及函数添加到全局的词法环境对象里面去;

 LexicalEnviroment: {
a: undefined,
b: undefined,
test: 对函数的一个引用
} //用声明的方式创建的函数
function test(params) { }
//用函数表达式创建的函数
var test1 = function(params) { }
//用var定义的变量
var a = 5;
var b;
//其他变量
c = 6;

定义一个声明函数和一个函数表达式来证明这一点,代码如下:

 f();
g(); function f() {
console.log("ff");
}
var g = function() {
console.log("gg");
}

得到如下结果:

 ff
e:\Code\JavaScript\day03\test2.js:2
g();
^ TypeError: g is not a function

函数f被正常执行,而函数g报错了

因为在预处理阶段,函数f的引用被放在LexicalEnviroment对象中了,而g没有,所以在调用时函数g()并不存在,所以报错。

改一下位置,这样就对了

 f();
var g = function() {
console.log("gg");
}
g(); function f() {
console.log("ff");
}

这点在var定义变量上的体现:

 console.log(a);
console.log(b); var a = 5;
b = 6;

这段代码的执行结果如下:

 undefined
e:\Code\JavaScript\day03\test3.js:2
console.log(b);
^ ReferenceError: b is not defined

可见,如上所说,以var方式定义的a被添加到全局LexicalEnviroment{ }(词法环境)对象中了,其值为undefined,而直接定义的b此时不存在,所以报错。

这就是全局预处理阶段的过程。

声明:

关于全局的词法环境对象LexicalEnviroment,在浏览器中就约等于window对象,该对象是属于JS解析器的东西,在不同的地方叫法不同,比如在Node中称为Execute Context(运行上下文对象)或许更合适一点,在ECMA -262标准中有其解释,但我们无需关心其具体含义,只是有这个概念便可。

JS的解析与执行过程—全局预处理阶段之全局词法环境对象的更多相关文章

  1. JS的解析与执行过程—函数预处理

    声明:之所以分为全局预处理与函数预处理,只是为了理解方便,其实在实际运行中二者是不分先后的. 函数预处理阶段与全局预处理的差别: 函数每调用一次,就会产生一个LexicalEnviroment对象,在 ...

  2. JS的解析与执行过程

    JS的解析与执行过程 全局中的解析和执行过程 预处理:创建一个词法环境(LexicalEnvironment,在后面简写为LE),扫描JS中的用声明的方式声明的函数,用var定义的变量并将它们加到预处 ...

  3. JS的解析与执行过程—全局预处理阶段之命名冲突的处理策略

    有如下代码: <body> <script> alert(f); function f() { console.log("fff"); } var f = ...

  4. js全局的解析与执行过程

    先看下面实例的执行结果: alert(a);//undefined alert(b);//报错 alert(f);//输出f函数字符串 alert(g);//undefined var a = 1; ...

  5. js函数的解析与执行过程

    function f(a,b,c){ alert(a);//函数字符串 alert(b); var b = 5; function a(){ } } f(1,2); //预处理 lexicalEnvi ...

  6. JS引擎线程的执行过程的三个阶段(二)

    继续JS引擎线程的执行过程的三个阶段(一) 内容, 如下: 三. 执行阶段 1. 网页的线程 永远只有JS引擎线程在执行JS脚本程序,其他三个线程只负责将满足触发条件的处理函数推进事件队列,等待JS引 ...

  7. JS引擎线程的执行过程的三个阶段(一)

    浏览器首先按顺序加载由<script>标签分割的js代码块,加载js代码块完毕后,立刻进入以下三个阶段,然后再按顺序查找下一个代码块,再继续执行以下三个阶段,无论是外部脚本文件(不异步加载 ...

  8. openWRT自学---基于backfire版本,分析其Make命令的执行过程和各阶段的主要产物

    准备阶段:从SVN下载backfire的编译环境(位置是:svn co svn://svn.openwrt.org/openwrt/branches/backfire),然后按照openWRT的要求, ...

  9. js的解析--预处理(三)

    js的解析与执行过程  分全局  {预处理阶段和执行阶段}  函数{预处理函数和执行阶段}   1/创建词法环境(环境上下文) LexicalEnvironment   === window { } ...

随机推荐

  1. Android数据分批载入-滑动究竟部自己主动载入列表

    Android数据分批载入-滑动究竟部自己主动载入列表 2014年5月9日 摘自:<Android高级开发实战-ui.ndk与安全> 本博文介绍怎样进行数据分批载入,在应用开发其中会常常使 ...

  2. 每一个程序猿都应该用MBP

    换笔记本的想法非常久了.前段时间换工作就想看换工作之后是什么情况吧. 可能工作配的笔记本就是MBP.后来发现是想多了,新工作的笔记本是Thinkpad X240. 配置全然够用了,8G内存+128G的 ...

  3. P 值(p value)与统计检验

    P 值是最常用的一个统计学指标,几乎统计软件输出结果都有P值. 统计学的观点,超过一定基准(比如 5%,其实是低于5%),就不能简单地认为这是偶然事件了,而是受到了外在的影响. 一般而言,为了确定从样 ...

  4. mac terminal终端怎么退出python命令行

    >>>使用 quit(), exit(), 或者Command+d,或者Command+z退出命令行.

  5. [APIO2014]回文串 后缀自动机_Manancher_倍增

    Code: // luogu-judger-enable-o2 #include <cstdio> #include <algorithm> #include <cstr ...

  6. TCP的连接管理

    创建连接:(三次握手) 第一步: 客户端向服务器发送一个报文,该报文不含有数据段,SYN=1,随机产生sequence number(随机产生可用于避免某些安全性攻击) 第二步: 服务器收到报文,为这 ...

  7. shell单引号屏蔽变量方法

    [goforit ~]$ name="玖零後大叔" [goforit~]$ echo $name 玖零後大叔 [goforit ~]$ echo "$name" ...

  8. 一个HelloWorld版的MySQL数据库管理器的设计与实现(源码)

    2011年,实习期间写了一个简单的数据库管理器. 今天,特意整理了下,分享给大家. 有兴趣的同学,可以下载源码,瞧瞧. 源码只有4个类:LoginGUI,DatabaseGUI,Record,MySQ ...

  9. tt

    Oracle报错处理 1.oem启动报错 解决方案:

  10. Unity Shader (二)Cg语言

    一.Cg基本数据类型 float 32位浮点数 half 16位浮点数 int 32位整型 fixed 12位定点数 bool 布尔数据 simpler* 纹理对象的句柄( the handle to ...