预编译
1.JS代码的执行步骤
- 语法分析: 主要扫描代码有没有语法上的错误(比如少些括号,写了中文符号)
- 预编译: 进行变量的声明提升,函数整体提升,函数执行前一刻的准备工作。
- 解释执行: 对js代码进行执行,解释一行,执行一行。
2.预编译的前奏
- 暗示全局变量:任何变量未经声明就赋值,此变量归全局所有。
- 一切全局变量都是window的属性
例如:
var a = 100;
console.log(window.a); //100
if(1){
a = 10;
}
console.log(window.a); //10
3.预编译
脚本代码块script执行前,系统执行的操作
- 创建一个GO对象,即window全局对象
- 查找全局变量声明(包括隐式全局变量声明,省略var声明),变量名作全局对象的属性,值为undefined
- 查找函数声明,函数名作为全局对象的属性,值为函数引用
例如
console.log(a); //undefined
console.log(func); //func
var a = 100;
function func(){
return 1;
}
注意:
- let和const也会有变量提升,但是在声明之前并不能访问到,因为存在一个暂时性死区。
- 函数声明出现在 if 等语句中的情况有点复杂,它仍然作用于脚本、模块和函数体级别,在预处理阶段,仍然会产生变量,它不再被提前赋值,所以下面的代码打印undefined。
console.log(foo);
if(true) {
function foo(){
}
}
- with关键字能改变代码块内的作用域,所以在使用的时候需要格外注意。这里打印2和underfined,因为在foo函数中,a会被变量提升,但是赋值的时候指定了对象o的作用域,所以只改变了o.a的值。
var a = 1;
function foo() {
var o= {a:3}
with(o) {
var a = 2;
}
console.log(o.a);
console.log(a);
}
foo();
- class 声明在全局的行为跟 function 和 var 都不一样。在 class 声明之前使用 class 名,会有变量提升,但是会抛错。
console.log(c);
class c{
}
4.函数执行上下文
函数在执行前会先做下面的操作
- 创建一个AO对象(执行期上下文)
- 找到函数体中定义的变量和函数形参,变量名作为AO的属性名,值为undefined
- 将实参和形参统一
- 将定义的函数名挂在AO的属性中,值为函数体。
如果有兴趣,可以看一下这一道面试题
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);
打印结果是
2
undefined
undefined
10
100
123
最后
感谢你能看到这里,如果你觉得这篇文章对你有点用的话,不妨点个赞再走呀~