全局预处理阶段
在js代码真正执行之前, 编译器会先对代码执行预处理, 看下面例子
console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
console.log(c); // undefined
console.log(d); // Function
var a = 1;
b = 2;
var c = () => {
alert(1);
}
function d(){
alert(2);
}
可以看到, 上面结果实际与我们预期差距很大, 那么编译器是如何进行js的预处理的呢
- 创建词法作用域(可以理解为一个js代码执行前就存在的全局变量)
- 扫描全局作用域下所有使用
var
关键字声明的变量, 将其赋值为undefined
; - 扫描全局作用域下所有使用 函数声明 方式声明的函数, 并将其赋值为对该函数的引用
这一操作被称为 声明提前 或者 声明前置 全局的预处理完成后, js代码开始正常执行
这里面还是有很坑的地方
-
let
和const
声明的变量不会被前置
console.log(a); // ReferenceError: b is not defined
const a = 1;
- 预处理阶段只会处理全局作用域下的变量声明和函数声明
var a = 1;
function b(){
var c = 2;
}
// 此时的GO对象
{
a: undefined,
b: Function
}
// b函数内声明的c变量没有被预处理
- 只有声明的方式声明的函数才会被前置
a(); // 1
b(); // ReferenceError: b is not defined
c(); // ReferenceError: b is not defined
d(); // ReferenceError: b is not defined
e(); // ReferenceError: b is not defined
f(); // ReferenceError: b is not defined
function a(){
console.log(1);
}
const b = function(){
console.log(2);
}
(function c(){
console.log(3);
})();
const d = new Function('console.log(4)');
- 遇到声明冲突时, 若为函数则覆盖, 若为变量则跳过
a(); // 2
console.log(b); // undefined
function a(){
console.log(1);
}
function a(){
console.log(2);
}
var b = 3;
var b = 4;
- 不安全的
typeof
typeof
除了用来检测目标类型之外还有检测变量是否被声明的作用
// a未声明, undefined, 不会报错
if (typeof a !== 'undefined'){
// do something
}
但是当es6的块级作用于出现之后, typeof也不安全了
typeof a; // ReferenceError: a is not defined
let a = 1;
函数预处理阶段
我们知道, 在块级作用域出现之前, js一直都是函数作用域, 类似的, 函数在真正执行之前也会经历一个预处理阶段
- 创建一个AO对象
- 找出函数形参以及函数作用域内的变量声明, 并赋值为undefined
- 将形参与实参的值相统一
- 找出作用域内所有的函数声明, 复制为其函数的引用
与全局预处理不同, 函数的预处理阶段多了对函数参数的处理
网友评论