js运行三部曲

1.语义分析

2.预编译

3.语法执行

# 预编译

# 函数声明整体提升

function test() {
        return 1;
}
//无论test写在前面还是写在后面 都可以正常输出
//因为预编译把函数声明往往放在了第一位
        test();
1
2
3
4
5
6

# 变量声明提升

console.log(a);  // 1
//因为声明了变量a var a被提升到 consloe.log 前面 打印undefined
//未声明变量 会报错 未定义
var a = 1;
1
2
3
4
var a = 123;        //声明变量a 并给a赋值123
var a = 123;        //拆分就是  var a; a = 123;
1
2
document.write(a);  //undefined
    var a = 123; 
//因为把声明变量a提到前面去了
1
2
3

# 暗示全局变量

imply global 一切声明的全局变量,全归window所有

# 例子

function test(){
        var a = b = 123; 
        //b未经声明被123赋值此时就归 window 所有 
        //window.b 值为123;
}
test();
1
2
3
4
5
6
//window就是全局的域
var b = 234;
//window就像一个仓库一样(电脑仓库)
var a = 123;
window {
    a : 123;
}
1
2
3
4
5
6
7

# 例子

function test() {
    var b = 123;
}
    test();
console.log(window.b); //打印undefined 
//因为b是局部变量
//一切声明全局变量的 都是window的属性 b不是全局变量
1
2
3
4
5
6
7
//window就是全局
var a = 123;
console.log(a); ---> console.log(window.a);
1
2
3

# 局部预编译过程

预编译发生在函数执行的前一刻

局部预编译过程

1.创建AO对象 Activation Object (执行期上下文)

2.找形参和变量声明,将变量和形参名作为AO对象属性名,值为undefined

3.将实参值和形参统一

4.在函数体里面找函数声明。值赋予函数体

    function fn(a) {
        console.log(a);

        var a = 123;
        console.log(a);

        function a() { }
        console.log(a);

        var b = function () { }
        console.log(b);
        function d() { }
    }
    fn(1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
第一步:  创建AO对象
第二步:AO {
                a :undefined,   //形参
                b :undefined,   //变量声明
}
第三步:AO {
                a :1,   //形参和实参值相统一
                b :undefined,
}
在函数体里面找函数声明function a (){},
把它的函数体赋给AO对象的属性(此时又找到了函数声明 d)
值赋予函数体
第四步:AO {
                a :function a() {},
                b :function () {},
                d :function d () {}
}

执行函数开始 (从上到下依次执行 对照着AO对象里面执行)
a = 123 ; //提升完的变量就不用管了(var a)
            AO {
                a :123;
                b :function () {},
                d :function d () {}
}

//打印结果为 function 123 123 function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 例子

function test(a, b) {
        console.log(a);
        c = 0;
        var c;
        a = 3;
        b = 2;
        console.log(b);
        function b() { }
        function d() { }
        console.log(b);
    }
    test(1);
AO {
        a : 3
        b : 2
        c : 0
        d : function d() {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 例子

function test(a, b) {
        console.log(a);         //fn
        console.log(b);         //undefined
        var b = 234;
        console.log(b);         //234
        a = 123;
        console.log(a);         //123
        function a() { }
        var a;
        b = 234;
        var b = function () { }
        console.log(a);         //123
        console.log(b);         //fn
    }
    test(1);
AO {
    a : 123,
    b : function () {},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

小规律

一旦有a变量 a函数重名 第一条输出的还是a 那么一定是函数a 因为预编译的第四部值赋予函数体

预编译不仅发生在函数体 还发生在全局

# 全局预编译过程

全局预编译过程

没有了函数预编译的第三步,

只需要创建GO对象找形参和变量声明和函数声明然后赋值

# 例子

console.log(a);         //undefined 因为var a提升上去了 没有赋值
var a = 123 ;
//全局里面放了函数声明 将函数也提升上去
function a() {
}
GO {
    a :123,
}
GO ==== >window
console.log(window.a);
console.log(a);     //两个相等
1
2
3
4
5
6
7
8
9
10
11

# 例子:

function test() {
var a = b = 123;
console.log(window.b);          //输出123
console.log(window.a);          //输出undefined 因为a在AO里不在window
}
AO{
    a: undefined--->123
}
GO{
    b:123
}
//因为b未经声明就赋值的话 归全局window(GO)所有
1
2
3
4
5
6
7
8
9
10
11
12

# 例子:

console.log(test);
function test(test) {
        console.log(test); //fn
    var test = 234;
        console.log(test); //234
    function test() {
    }
}
test(1);
var test=123;
步骤:

创建GO对象 GO{
test: function() {}
}
执行函数 执行的前一刻进行预编译(执行上下文)

创建AO对象 AO{
test: function() {}
}
//AO和GO里面同时有 先找AO的 AO里面没有 再找GO(找近处的来)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 例子:

var global = 100function fn() {
console.log(global);
}
fn();   //100

Go {
        global: 100
        fn: function fn() {}
}

AO {
}
//AO里面没有 去GO里面找 输出100
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 例子:

a = 100;
function demo(e) {
        function e() { }
        arguments[0] = 2;
        console.log(e);
     if (a) {
         var b = 123;
         function c() {
          }
}
var c;
    a = 10;
var a;
    console.log(b);
    f = 123;
    console.log(c);
    console.log(a);
}
var a;
demo(1);
console.log(a);
console.log(f);
步骤:

    GO {
            a: 100,
            demo : function () { }
    }
    AO {
            e: 1, 2,
            b: function e() { }, undefined,
            c: undefined, function () { }
            a: undefined; 10
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 练习题

var str = false + 1;
document.write(str); 
//相加隐式类型转换为number false转换为number为0 打印1
1
2
3
var demo = false == 1;
document.write(demo); 
//判断false是不是等于1 不等于 输出布尔值false
1
2
3
if (typeof (a) && -true + (+undefined) + "") {    
// ”undefined“ && "NAN"
        document.write('基础扎实');
}
1
2
3
4
if (11 + "11" * 2 == 33) {                
//乘法两边都要转换成数字 所以字符串11=11
        document.write("基础扎实")
}
1
2
3
4
    undefined        bar
(window.foo || (window.foo = 'bar')); 
//先看后面的括号里面的
//window.foo的值'bar'
1
2
3
4

# 总结例子

a = 100;
function demo(e) {
        function e() { }
        arguments[0] = 2;
        //arguments[0]代表第一位实参
        //arguments[0]改其实e就改
        document.write(e);//2
if (a) {
        var b = 123;
        function c() {
            }
    }
        var c;
        a = 10;
        var a;
        document.write(b); //undefined
        f = 123;
        document.write(c); 
        //理应是fn因为语言规定不能给if语句里面写函数所以是undefined
        document.write(a); //10
    }
    var a;
    demo(1);
    document.write(a); //外部GO里面a100
    document.write(f); //123
第一步:AO {
                e: undefined
                b: undefined
                c: undefined
                a: undefined
    }
第二步:AO {
                e: 1
                b: undefined
                c: undefined
                a: undefined
    }
第三四步:AO {
                e: 2
                b: undefined
                c: function c() { }
                a: 10
    }
//因为f在函数体AO里面没有,所以就暗示全局变量window,因为window就是GO所以
            GO{
                f: 123
                a: 100
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48