暗示全局变量

什么是暗示全局变量(imply global variable)呢?
JavaScript中所有的变量都归window对象所有。如下:

  1. var a = 1;
  2. b = 2;
  3. // 可以理解成这样
  4. // window = {
  5. // a: 1,
  6. // b: 2
  7. // }

JavaScript中,如果不使用var关键字进行变量声明,那么这个变量就是「全局变量」。

  1. function test() {
  2. var a = b = 1;
  3. c = 2;
  4. }
  5. test()
  6. console.log(b); // 1
  7. console.log(c); // 2
  8. console.log(a); // error,a 不是全局变量

预编译

因为JavaScript是解释型开发语言,所以它的执行步骤是:

  1. 检查通篇的语法错误
  2. 预编译
  3. 解释一行执行一行
    1. console.log(a); // error,检查语法错误

在「预编译」的过程中,函数声明会被整体提升,所以你在函数声明前调用函数还是函数声明后调用函数是一样的

  1. test(); // 1
  2. function test() {
  3. console.log(1);
  4. }
  5. test(); // 1
  6. console.log(a); // function()
  7. function a(){}

在声明变量的时候只有变量的提升的,赋值是不会提升的。

  1. console.log(a); // undefind
  2. var a = 1;
  3. var b = 3; // 变量声明且赋值
  4. console.log(c); // Error,预编译的过程中发现 c 没有定义
  5. // 以上代码在预编译的过程中其实值这样的
  6. // 在预编译时我们不看赋值,只把变量的声明提升,因此若在赋值前打印会提示 undefined
  7. var a;
  8. var b;
  9. a = 1;
  10. b = 3;

那么到底什么是预编译???
预编译就是全局代码和函数执行之前执行的步骤。

预编译的执行过程可以分为三步:

  1. 寻找函数的形参和变量声明,赋值为undefind
  2. 将实参的值赋值给形参
  3. 找函数声明且赋值函数体

    我更愿意把预编译理解成五步:

    1. 执行函数
    2. 变量赋值

我们先来看函数执行上下文。
Activation Object 活跃对象,简称AO,或者「函数上下文」。

  1. function test(a) {
  2. console.log(a); // funtion
  3. var a = 1;
  4. console.log(a); // 1
  5. function a() {}
  6. console.log(a) // 1
  7. var b = function () {};
  8. console.log(b); // function
  9. function d() {}
  10. }
  11. test(2);
  1. // 以上函数执行的预编译过程是
  2. // 0、创建 AO 对象
  3. // 1、寻找函数形参和变量声明,所以我们能找到形参 a 和变量声明 b
  4. AO = {
  5. a: undefind,
  6. b: undefind
  7. }
  8. // 2、实参数据赋值给形参
  9. AO = {
  10. a: undefind => 2,
  11. b: undefind
  12. }
  13. // 3、寻找函数声明且赋值函数体,我们能看到 a 和 d 都是函数声明
  14. AO = {
  15. a: undefind => 2 => function(),
  16. b: undefind,
  17. d: function()
  18. }
  19. // 4、执行函数
  20. // 5、变量赋值
  21. // 第 2 行执行的时候,a 是 function() ,所以打印 function
  22. // 第 3 行,a 被赋值为 1
  23. // 第 4 行,打印 a 为 1
  24. // 第 5 行,a 在预编译阶段已经赋值为 function 所以这行忽略
  25. // 第 6 行,a 无变化,所以打印 1
  26. // 第 7 行,b 赋值为 function()
  27. // 第 8 行,打印 b 为 function()
  28. // 第 9 行,d 在预编译阶段赋值为 function

以上就是一个函数执行上下文的一个全过程。

Global Object全局上下文,简称GO,和AO执行过程是一样的,只不过GO不存在函数实参对应过程。

  1. var a = 1;
  2. function a() {}
  3. console.log(a);
  1. // 以上代码的执行过程
  2. // 0、创建 GO 对象
  3. // 1、寻找变量声明
  4. GO = {
  5. a: undedfind
  6. }
  7. // 2、寻找函数声明
  8. GO = {
  9. a: undedfind => function()
  10. }
  11. // 3、执行代码
  12. // 4、变量赋值
  13. // 第 1 行,把 a 赋值为 1
  14. // 第 2 行,预编译阶段已经执行所以忽略
  15. // 第 3 行,打印 a 为 1

下面再看几个例子:

  1. function test() {
  2. var a = b = 1;
  3. console.log(a); //
  4. }
  5. // 自己不存在的会去GO对象中寻找
  6. GO = {
  7. b: undefind => 1
  8. }
  9. AO = {
  10. a: undefind => GO.b => 1
  11. }
  1. var b = 3;
  2. console.log(a); // function
  3. function a(a) {
  4. console.log(a); // function
  5. var a = 2;
  6. console.log(a); // 2
  7. function a() {}
  8. var b = 5;
  9. console.log(b); // 5
  10. }
  11. a(1);
  12. // 执行过程
  13. GO = {
  14. b: undefind => 3
  15. a: function
  16. }
  17. AO = {
  18. a: undefind => 1 => function => 2
  19. b: undefind => 5
  20. }
  1. function test() {
  2. console.log(b); // undefind
  3. if (a) { // if 语句执行的时候才会判断,这里看的是预编译
  4. var b = 2;
  5. }
  6. c = 3;
  7. console.log(c); // 3
  8. }
  9. var a;
  10. test();
  11. a = 1;
  12. console.log(a); // 1
  13. // 执行过程
  14. GO = {
  15. a: undenfind => 1
  16. test: function
  17. c: undefind => 3
  18. }
  19. AO = {
  20. b: undefind
  21. }