前言 :
了解 JS 解析与执行过程,可以帮助我们更好的掌握 JS 这门语言特性,而不是仅仅停留在使用阶段。JS 解析与执行过程 大概可以分为两种情况,全局状态下和函数内部状态下。每种情况下又分为预处理阶段和执行阶段。(既:全局预处理阶段,全局执行阶段,函数预处理阶段,函数执行阶段。)
- 全局预处理阶段 ?
首先让我们来思考一个问题,在全局预处理阶段的时候,JS 会做一些什么事情呢 ?
- 全局生成一个 LexicalEnviroment (JS 词法环境对象 ) 。
- 将用 var 声明的变量 和 用声明方式创建的函数,加到 LexicalEnviroment (JS 词法环境对象 ) 中。
【注意】在全局预处理阶段, LexicalEnviroment === window 。
- 代码示例 ?
/* 全局预处理阶段
LexicalEnviroment = window{
a: undefined,
b: undefined,
c: undefined,
A: 函数 A 的引用
B:undefined
}
*/
/* 全局执行阶段(一边执行,数值一边改变)
LexicalEnviroment = window{
a: 5,
b: undefined,
c: 7,
d: 9,
A: 函数 A 的引用
B:函数 B 的引用
}
*/
var a = 5;
console.log(a)// 5
var b;
console.log(b)// undefined
console.log(c)// undefined
var c = 7;
console.log(d)// Uncaught ReferenceError: d is not defined
d = 9;
alert(A);// function A(){console.log('AAA');}
alertB(B);// undefined
function A(){
console.log('AAA');
}
var B = function(){// 函数表达式,相当于变量赋值
console.log('BBB');
}
- JS 处理命名重复问题 ?(只会发生在预处理阶段)
再来思考一个问题,如果代码中命名重复,JS 会如何去做 ?
- 先扫描函数声明后扫描变量(var 声明)。
- 处理函数声明有冲突,会覆盖 。
- 处理变量声明有冲突,会忽略 。
【总结】:函数和变量冲突,变量忽略,函数覆盖。函数和函数命名冲突,执行阶段更新值。变量和变量命名冲突,执行阶段更新值。
- 代码示例 ?
/* JS 处理命名重复问题 */
/* 全局预处理阶段
LexicalEnviroment = window{
f: 函数 f 的引用
m: 函数 m 的引用
}
*/
/* 全局执行阶段(一边执行,一边修改)
LexicalEnviroment = window{
f: 函数 f 的引用
m: 函数 m 的引用
}
*/
alert(f)//function f(){console.log(f);}
var f = 5;
function f(){
console.log(f);
}
alert(m)//function f(){console.log(f);}
function m(){
console.log(m);
}
var m = 5;
- 全局执行阶段 ?
执行代码的过程中,会把值赋值进 LexicalEnviroment (JS 词法环境对象 )中,没有的变量和函数会新增进去。
【注意】:执行阶段,代码一边执行, LexicalEnviroment (JS 词法环境对象 )中数值一边改变,所以操作,使用变量和函数的时候,要在改变之后。否则会出错或者出现 undefined 。
- 代码示例 ?
/* 全局预处理阶段
LexicalEnviroment = window{
a: undefined,
f: 函数 f 的引用,
g: undefined
}
*/
/* 全局执行阶段:(一边执行,一边修改)
LexicalEnviroment = window{
a: 5,
f: 函数 f 的引用,
g: 函数 g 的引用,
b: 6,
}
*/
alert(a);// undefined
alert(b);// Uncaught ReferenceError: b is not defined
alert(f);// function f(){console.log('f');}
alert(g);// undefined
var a = 5;
b = 6;
alert(b);// 6
function f(){
console.log('f');
}
var g = function(){// 函数表达式,相当于变量的赋值
console.log('g');
}
alert(g);// function(){console.log('g');}