预编译
变量提升
JS 在执行函数前,会先预编译,把用 var 声明的变量的声明提升到前面。
只有一个语句 console.log(a),这样子会直接报错 a is not defined。
jsconsole.log(a); // a is not defined
声明变量,但是不赋值,则会得到 undefined
jsvar a; console.log(a); //undefined
先打印,再声明变量 ( 执行代码前,会先进行一次预编译,把 var 变量的声明提升到前面。)
jsconsole.log(a); // undefined var a;
代码等效于
jsvar a; console.log(a);
变量提升只会把变量的声明提升到前面,赋值则不会提升到前面。
jsconsole.log(a); // undefined var a = 123; console.log(a); // 123
代码等效于
jsvar a; console.log(a); // undefined a = 123; console.log(a); // 123
函数提升
函数声明整体提升,函数调用不提升
jsconsole.log(test); // function test() {console.log(222)} test(); // 222 console.log(111); // 111 function test() { console.log(222); }
等效于
jsfunction test() { console.log(222); } console.log(test); test(); console.log(111);
使用使用变量声明函数,则走的是变量提升路线,而不是函数声明路线
jsconsole.log(test); // undefined test(); // test is not a function var test = function () { console.log(111); };
函数内部也会有变量提升,这时候会先预处理全局的,再预处理函数的,且函数内的变量、函数提升不能提升到函数外。
jsfunction mytest1() { console.log(a); // undefined b(); // 456 var a = 123; function b() { console.log(456); } } mytest1(); console.log(a); // a is not defined
等效
jsfunction mytest1() { function b() { console.log(456); } var a; console.log(a); b(); a = 123; } mytest1(); console.log(a);
隐式的全局变量 如果函数内部的变量没有定义,直接赋值,则会直接变成全局变量
jsfunction test() { a = 123; } test(); console.log(a); // 123 var a = 1; var b = 1; function func() { var a = 2; b = 2; } func(); console.log(a); // 1 console.log(b); // 2
预编译
全局预编译
- 创建 GO 对象(Global Object)
- 找变量声明,将变量作为 GO 属性(在浏览器中的话,实际上就是挂载到 window 对象上),值为 undefined
- 找函数声明,作为 GO 属性值为函数体
局部预编译
- 创建 AO 对象(Activation Object)
- 找形参和变量声明,将变量和形参作为 AO 属性,值为 undefined
- 实参和形参统一(将实参的值赋值给形参)
- 找函数声明,值赋予函数体
总结
- GO 对象是全局预编译,所以它优先于 AO 对象所创建和执行。
- 从结果上看是函数优先,但从过程来看是变量优先,因为变量提升后被之后的函数提升给覆盖掉了。