前言:
对于引擎本身拿到代码该如何处理,执行出运算结果?不妨今天就深层次的来解答引擎是如何进行预编译的。
在预编译阶段,JavaScript引擎会做以下几件事情:
- 创建作用域链:JavaScript中的作用域是通过作用域链来实现的,预编译阶段会创建作用域链,确定变量和函数的作用域关系。
- 提升变量声明:JavaScript中的变量声明(使用
var关键字)和函数声明会被提升到当前作用域的顶部。这意味着在预编译阶段,变量和函数的声明会被提升到作用域的顶部,但初始化(赋值)部分不会被提升。 - 函数声明优先:在预编译阶段,函数声明会被提升到作用域的顶部,并且在变量声明之前。这意味着无论函数声明在代码中的位置如何,都可以在声明之前调用这些函数。
- 变量声明提升:变量声明也会被提升到作用域的顶部,但初始化部分不会提升。变量的初始化是在代码执行阶段进行的。
作用域链: 作用域是执行期上下文对象的集合,这种集合呈链式连接,我们把这种链式关系称之为作用域链。
简单来说:预编译就是代码在执行前需要进行编译操作,用于确定代码之间的各种关联
正文:
引擎是如何先编译在执行编译器上的代码?
方法:
发生在全局作用域
- 创建GO对象
- 找变量声明,将变量名作为GO的属性名,值为undefined
- 在全局找函数声明,将函数名作为GO的属性名,值为该函数体
发生在函数体内作用域:
- 创建一个AO对象
- 找形参和变量声明,将形参和变量名作为AO的属性名,值为undefined
- 形参和实参统一
- 在函数体内找函数声明,将函数名作为AO的属性名,值为该函数体
function fn(a) {
console.log(a);
var a = 123
console.log(a);
function a() {} //
console.log(a);
var b = function() {}
console.log(b);
function c() {}
var c = a
console.log(c);
}
fn(1)
首先
- 在全局作用域内创造GO对象
- 找变量声明:这段代码并没有
- 函数声明:
GO:{
fn: function () {}
}
在编译完全局作用域内后执行全局作用域,引擎就来到了fn()函数的调用。
其次 4. 函数作用域内创建一个AO对象 5. 找形参和变量声明,将形参和变量名作为AO的属性名,值为undefined
AO:{
a: undefined
b: undefined
c: undefined
}
- 形参和实参统一
AO:{
a: undefined 1
b: undefined
c: undefined
}
- 在函数体内找函数声明,将函数名作为AO的属性名,值为该函数体
AO:{
a: undefined 1 function
b: undefined
c: undefined function
}
到此预编译结束 ,进行代码执行。
最终结果:
function fn(a) {
console.log(a);//function
var a = 123
console.log(a);//123
function a() {} //
console.log(a);//123
var b = function() {}
console.log(b);//function
function c() {}
var c = a
console.log(c); //123
}
fn(1)
// AO:{
// a: undefined 1 function 123
// b: undefined function
// c: undefined function 123
// }
最终在终端结果运行正确。
完美解答:
var global = 100
function fn() {
console.log(global);
}
fn()
这道题该如何解释?
及格解答: 因为函数体内找不到global,跳到外层作用域找,找到global 的值为100。
这个解答是正确的,但并不能让大厂面试官认为你深刻了解。而我之前介绍的方法站在引擎的角度彻底来剖析解答,很好的解决了。看看大家的解答...