简介
当浏览器拿到一段JavaScript
代码的时候并不会去直接执行它,浏览器引擎会在执行JavaScript
代码之前对其进行预编译。
总的而言就是下列两个步骤:
javascript
预编译:就是通过语法分析和预解析构造合法的语法分析树,读取变量和函数的声明,并确定其作用域即生效范围。javascript
执行:执行具体的代码,JavaScript
引擎在执行每个函数实例时,都会创建一个执行环境和活动对象(它们属于宿主对象,与函数实例的生命周期保持一致)
预编译阶段的一部分工作就是找到所有的变量和函数声明,并用合适的作用域与之关联起来。
因此,包括变量和函数在内的所有声明都会在其他代码执行前首先被处理
函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖
GO
:全局上下文 全局预编译AO
:函数上下文 函数预编译
函数声明
- 解析器在向执行环境中夹在数据时,对函数声明和函数表达式并非一视同仁。
- 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)。
- 说白了就是,用函数声明形式定义的函数支持变量提升 ,而函数表达式形式的不行。
// 函数声明形式定义函数
foo();
function foo() {
console.log("成功");
}
// 结果:成功
// 上面代码相当于
function foo() {
console.log("成功");
}
foo();
// 函数表达式
foo();
var foo = function foo() {
console.log("成功");
}
// 结果:TypeError:foo is not a function
// 即使是具名的函数表达式,名称标识符在赋值之前也无法再所在作用域中使用
fn(); // TypeError
vm(); // ReferenceError
var fn = function vm() {
console.log('1')
};
变量提升
var
定义的变量有变量提升
let
、const
定义的变量和常量不会变量提升
console.log(a) // undefined
var a = 1
关卡
console.log(a) // [Function: a]
function a(a) {
var a = 10;
var a = function () {
}
}
var a = 1;
/**
* 相当于
* 函数提升(优先于变量提升):function a(a) {}
* 变量提升:var a
* console.log(a)
* a = 1
*/
function test() {
var a = b = 1; // 这里相当于 var a = 1 b = 1 b前面没有var,是定义在全局的
}
test();
console.log(b) // 1
if (!("a" in window)) {
var a = 1;
}
console.log(a); // undefined
/**
* 上面代码相当于
* var a
* if (!("a" in window)) { // 已经定义了a = undefined,所以不走这个if语句
* a = 1;
* }
* console.log(a);
*/
function test(a,b) {
console.log(a); // 1
c = 0;
var c;
a = 5;
b = 6;
console.log(b); // 6
function b(){}
function d(){}
console.log(b) // 6
}
test(1)
/*
* AO = {
* a: undefined -> 1 -> 5
* b: undefined -> function b(){} -> 6
* c: undefined -> 0
* d: function d(){}
* }
*/
var b = 3;
console.log(a); // function a(){}
function a(a) {
console.log(a); // function a(){}
var a = 2;
console.log(a); // 2
function a() {}
var b = 5;
console.log(b); // 5
}
a(1);
/*
* GO = {
* b: undefined -> 3
* a: undefined -> function a() {}
* }
* AO = {
* a: undefined -> 1 -> function a(){} -> 2
* b: undefined -> 5
* }
*/
function test(){
console.log(b);
if(a){
var b = 2;
}
c = 3;
console.log(c);
}
var a;
test();
a = 1;
console.log(a);
/*
* GO = {
* a: undefined -> 1
* test: fucntion(){...}
* c: undefined -> 3
* }
* AO = {
* b: undefined
* }
*/
a = 1;
function test(e){
function e(){}
arguments[0] = 2;
console.log(e);
if(a){
var b = 3;
}
var c;
a = 4;
var a;
console.log(b);
f = 5;
console.log(c);
console.log(a);
}
var a;
test(1);
console.log(a);
console.log(f);
/*
* GO = {
* a: undefined -> 1
* test: function(){...}
* f: undefined -> 5
* }
* AO = {
* e: undefined -> 1 -> function e(){} -> 2
* b: undefined
* a: undefined -> 4
* c: undefined
* }
*/
a()
var a = c = function() {
console.log(2)
}
a()
function a() {
console.log(1)
}
a();
(function(b) {
b(), c()
var b = c = function a() {
console.log(3)
}
b()
})(a)
c()
// 1 2 2 2 2 3 3
// 将 var(变量提升) 和函数声明提到最上面 上面代码就相当于下面的
var a;
function a() {
console.log(1)
}
a(); // 1
a = c = function() {
console.log(5)
}
a(); // 2 a后面又定义了,所以覆盖了
a(); // 2
(function(b) {
var b, c
b(); // 2 b是形参,就是传入的a
c(); // 2 var b=c=xxx 这里c相当于没有加var 不会预编译,这里c直接查找到外部作用域的c
b = c = function a() {
console.log(3);
}
b(); // 3
})(a); // 走到这里 a已经被赋值表达式重新赋值
c(); // 3 由于没加var 的原因 c已经被立即执行函数内部的赋值表达式改变了值 这里是3
发表评论