暗示全局变量
什么是暗示全局变量(imply global variable)呢?
在JavaScript中所有的变量都归window对象所有。如下:
var a = 1;b = 2;// 可以理解成这样// window = {// a: 1,// b: 2// }
在JavaScript中,如果不使用var关键字进行变量声明,那么这个变量就是「全局变量」。
function test() {var a = b = 1;c = 2;}test()console.log(b); // 1console.log(c); // 2console.log(a); // error,a 不是全局变量
预编译
因为JavaScript是解释型开发语言,所以它的执行步骤是:
- 检查通篇的语法错误
- 预编译
- 解释一行执行一行
console.log(a); // error,检查语法错误
在「预编译」的过程中,函数声明会被整体提升,所以你在函数声明前调用函数还是函数声明后调用函数是一样的
test(); // 1function test() {console.log(1);}test(); // 1console.log(a); // function()function a(){}
在声明变量的时候只有变量的提升的,赋值是不会提升的。
console.log(a); // undefindvar a = 1;var b = 3; // 变量声明且赋值console.log(c); // Error,预编译的过程中发现 c 没有定义// 以上代码在预编译的过程中其实值这样的// 在预编译时我们不看赋值,只把变量的声明提升,因此若在赋值前打印会提示 undefinedvar a;var b;a = 1;b = 3;
那么到底什么是预编译???
预编译就是全局代码和函数执行之前执行的步骤。
预编译的执行过程可以分为三步:
- 寻找函数的形参和变量声明,赋值为
undefind - 将实参的值赋值给形参
- 找函数声明且赋值函数体
我更愿意把预编译理解成五步:
- 执行函数
- 变量赋值
我们先来看函数执行上下文。Activation Object 活跃对象,简称AO,或者「函数上下文」。
function test(a) {console.log(a); // funtionvar a = 1;console.log(a); // 1function a() {}console.log(a) // 1var b = function () {};console.log(b); // functionfunction d() {}}test(2);
// 以上函数执行的预编译过程是// 0、创建 AO 对象// 1、寻找函数形参和变量声明,所以我们能找到形参 a 和变量声明 bAO = {a: undefind,b: undefind}// 2、实参数据赋值给形参AO = {a: undefind => 2,b: undefind}// 3、寻找函数声明且赋值函数体,我们能看到 a 和 d 都是函数声明AO = {a: undefind => 2 => function(),b: undefind,d: function()}// 4、执行函数// 5、变量赋值// 第 2 行执行的时候,a 是 function() ,所以打印 function// 第 3 行,a 被赋值为 1// 第 4 行,打印 a 为 1// 第 5 行,a 在预编译阶段已经赋值为 function 所以这行忽略// 第 6 行,a 无变化,所以打印 1// 第 7 行,b 赋值为 function()// 第 8 行,打印 b 为 function()// 第 9 行,d 在预编译阶段赋值为 function
以上就是一个函数执行上下文的一个全过程。
Global Object全局上下文,简称GO,和AO执行过程是一样的,只不过GO不存在函数实参对应过程。
var a = 1;function a() {}console.log(a);
// 以上代码的执行过程// 0、创建 GO 对象// 1、寻找变量声明GO = {a: undedfind}// 2、寻找函数声明GO = {a: undedfind => function()}// 3、执行代码// 4、变量赋值// 第 1 行,把 a 赋值为 1// 第 2 行,预编译阶段已经执行所以忽略// 第 3 行,打印 a 为 1
下面再看几个例子:
function test() {var a = b = 1;console.log(a); //}// 自己不存在的会去GO对象中寻找GO = {b: undefind => 1}AO = {a: undefind => GO.b => 1}
var b = 3;console.log(a); // functionfunction a(a) {console.log(a); // functionvar a = 2;console.log(a); // 2function a() {}var b = 5;console.log(b); // 5}a(1);// 执行过程GO = {b: undefind => 3a: function}AO = {a: undefind => 1 => function => 2b: undefind => 5}
function test() {console.log(b); // undefindif (a) { // if 语句执行的时候才会判断,这里看的是预编译var b = 2;}c = 3;console.log(c); // 3}var a;test();a = 1;console.log(a); // 1// 执行过程GO = {a: undenfind => 1test: functionc: undefind => 3}AO = {b: undefind}
