写在前面
为什么要深入学习JavaScript基础?
JavaScript 堪称世界上被人误解最深的编程语言。虽然常被嘲为“玩具语言”,但在它看似简洁的外衣下,还隐藏着强大的语言特性。 JavaScript 目前广泛应用于众多知名应用中,对于网页和移动开发者来说,深入理解 JavaScript 就尤为必要。源文地址
个人心得:
- 源码阅读与学习受阻(更深入了解框架的运作方式,后期学习与使用框架会有事半功倍的效果,学习写代码设计思想思维方式,学习新的框架更容易触类旁通)
- 个人能力提升受阻(基础决定了你的职业道路能走多远,甚至是解决问题的速度有多快,方法有多好)
GO、AO、预解析
导语
本文将主要以习题实战的方式让大家有更透彻的理解,下面开始今天的学习:
GO、AO、预解析究竟是什么? 在了解这些之前我们先来看看JavaScript语言的执行过程,大致分为下面几个步骤:
- 语法检查:对整体代码进行词法分析,语法分析
- 代码预解析:生成GO、AO对象(也称作预编译)
- 解释执行:逐行运行代码
注意: 在javascript解析过程中,如果遇到错误,会直接跳出当前的代码块,直接执行下一个script代码段,因此在同一个script内的代码段有错误的话就不会执行下去。但是它不会影响下一个script内的代码段。
了解了JavaScript执行过程,下面我们来看看对于这三个关键词的简单解释:
-
GO
- 全局执行上下文
- Global Object 全局作用域
-
AO
- 函数执行上下文
- Activation Object 局部作用域
- 当一个方法被 调用 的时候(执行之前)会形成一个局部作用域AO
-
预解析
- 函数执行之前需要执行的一个步骤
看了这么多文字,你可能无法理解,没关系,我们直接进入实战练习,看看他们的执行过程是怎样的。
GO
-
寻找变量声明
-
寻找函数声明并赋值
-
执行
代码示例:
1. console.log(a) 2. var a = 1 3. function a() { 4. console.log(2) 5. } 6. console.log(a)
JavaScript解析器在执行这段代码之前,首先进行词法分析(上面代码没有错误,直接通过),接着进入预解析环节,生成GO对象,GO对象内包含默认属性例如:window: Object,this: window(浏览器环境下),最后再执行改代码!
所以在第二步预解析生成GO对象的时候,是这样的
| GO | |
|---|---|
| this | window |
| window | (object) |
| ... | ... |
下面我们写出他的详细过程:
-
寻找变量声明:(var关键字)
2. var a = 2;找到第二行代码,并提升var a ,此时的GO对象如下:
GO this window window (object) a undefined ... ... 可以看到GO对象内部多了一个a属性,值为undefined
-
寻找函数声明(function关键字)
3. function a() { 4. console.log(2) 5. }GO this window window (object) a function a() {...} ... ... - 此时的a 从 undefined 变成了 function
-
执行
1. console.log(a) // function(){...} 2. a = 1 // a = 1, 此时GO内的a属性的值由function改为了1 6. console.log(a) // 1 程序执行完毕下面是整个GO对象变化的过程
GO this window window (object) a undefined --> function a(){...} --> 1 ... ...
至此,对于GO,相信你有了一定的了解,AO 与 GO 执行方式相似,下面我们继续看 AO:
AO
AO的执行过程分为如下四个步骤:
- 寻找形参和变量声明
- 实参值赋值给形参
- 找函数声明
- 执行
继续看代码:
1. var a = 1
2. function test(c){
3. var b = 2
4. console.log(a)
5. console.log(b)
6. console.log(c)
7. }
8. test(3)
预编译阶段,GO生成(省略初默认字段)
| GO | |
|---|---|
| a | undefined |
| test | function () {...} |
生成AO如下:
| AO | function test |
|---|---|
| c | undefined |
| b | undefined |
接着运行代码:
1. var a = 1 // GO.a = 1
7. test(3) //
执行test(3)
3. b = 2 // AO.b = 2
4. console.log(a) // 1, 当前ao没有a属性,向上查找 GO.a,具体逻辑查看后面的作用域链
5. console.log(b) // 2, AO.b
6. console.log(c) // 3, AO.c
注意:AO只有在函数执行前才会生成AO对象,未被调用的函数不会生成AO对象,test函数执行完毕,AO对象在没有被其他地方引用的情况下,会被立即销毁。
趁热打铁,快速写出下面代码AO对象
function test(a){
console.log(a);
var a = 1;
console.log(a);
function a(){}
console.log(a);
var b = function(){}
console.log(b);
function d(){}
}
test(2);
| GO | |
|---|---|
| test | function(){...} |
| AO | |
|---|---|
| a | undefined -> function(){...} --> 1 |
| b | undefined --> function(){...} |
| d | function(){...} |
上面代码运行结果
function test(a){
console.log(a); // function a(){}
var a = 1;
console.log(a); // 1
function a(){}
console.log(a); // 1
var b = function(){}
console.log(b); // function b
function d(){}
}
test(2);
下面是练习
function test(){
a = 1;
function a(){}
var a = 2;
return a;
}
console.log(test());
function test(){
console.log(a);
var a = b = 3;
}
test();
console.log(b);
function test(){
console.log(b);
if(a){
var b = 3;
}
}
test();
var a = 4;
function test(){
return b;
var b = 3;
}
test();
var a = 4;
console.log(fun1);
console.log(fun2);
function fun1() {
console.log('函数fun1');
}
var fun2 = function () {
console.log('函数fun2');
}
console.log(fun1);
console.log(fun2);
var a = 2
function test(b) {
console.log(a)
var a
a = 3
a = 4
console.log(a)
}
test(2)
| GO | |
|---|---|
| this | window |
| window | (object) |
| a | undefined --> 2 |
| test | function test(){...} |
| AO | |
|---|---|
| this | window |
| window | (object) |
| b | undefined |
| a | undefined --> 3 --> 4 |
| test | function test(){...} |
AO、GO 实战练习
function a(b) {
console.log(b);
function b(){
console.log(b);
}
b();
}
a(1)
function a(b){
console.log(b)
var b = function(){
console.log(b)
}
}
a(2)
console.log(fun);
function fun(fun){
console.log(fun);
var fun = 2;
console.log(fun);
function fun(){}
}
fun(1);
var fun = 1;
碰到
return语句
function test(){
return a;
a = 1;
function a(){}
var a = 2;
}
碰到if语句
function test(e){
console.log(e);
function e(){}
arguments[0] = 2;
console.log(e);
if(a){
var b = 3;
}
var c;
a = 4;
var a;
console.log(b);
f = 5;
console.log(c);
console.log(a);
}
var a;
test(1);
console.log(a);
console.log(f);
作用域链
AO/GO
- AO:函数执行期上下文
- GO:全局执行期上下文 (函数执行完成之后AO会被销毁,再次执行AO会重新生成)
作用域链
- 用于保存这些上下文的一个容器
scope
- 函数创建时,生成的一个JS内部的隐式属性。
- 函数存储作用域链的容器
function a(){
function b(){
var b = 2;
}
var a = 1;
b();
}
var c = 3;
a();
function test1(){
function test2(){}
var a = 1;
return test2;
}
var c = 3;
var test3 = test1();
test3();