前言
本文整理了前端面试高频出现的让你说(猜)打印输出类问题,如果对答案有不一样见解的同学欢迎评论区补充讨论,当然有问题,也欢迎在评论区指出。
引用+参考 www.pianshen.com/article/846…
先来道测试题
- 如果下面这道题能够正确知道打印顺序,便没必要看这篇文章,省点时间打球、约会去吧
function fn(a, c) {
console.log(a) //function a(){}
var a = 123
console.log(a) //123
console.log(c) //function c(){}
function a() {
}
if (false) {
var d = 678
}
console.log(d) //undefined
console.log(b) //undefined
var b = function () {
}
console.log(b) //function(){}
function c() {
}
console.log(c) //function c(){}
}
fn(1, 2)
全面分析js引擎的执行过程,分为三个阶段
1、语法分析
js的代码块加载完毕之后,会首先进入到语法分析阶段,该阶段的主要作用:
- 分析该js脚本代码块的语法是否正确,如果出现不正确会向外抛出一个语法错误(syntaxError) ,停止该js代码的执行
2、预编译阶段
通过语法分析阶段之后,语法都正确时,将进入预编译阶段
在分析预编译阶段之前,我们先来了解一下js的运行环境,运行环境主要由三种:
1、全局环境(js代码加载完毕后,进入到预编译也就是进入到全局环境)
2、函数环境(函数调用的时候,进入到该函数环境,不同的函数,函数环境不同)
3、eval环境(不建议使用,存在安全、性能问题)
每进入到一个不同的运行环境都会创建 一个相应的执行上下文(execution context) ,那么在一段js程序中一般都会创建多个执行上下文,js引擎会以栈的数据结构对这些执行进行处理,形成函数调用栈(call stack), 栈底永远是全局执行上下文(global execution context) ,栈顶则永远时当前的执行上下文。
(1)创建函数调用栈
函数调用栈就是使用栈存取的方式进行管理运行环境,特点是先进后出,后进后出
说明:不同的运行环境执行都会进入到代码预编译和执行两个阶段
function parent() {
var A_context = "parent content";
function child() {
var B_context = "child content";
}
child()
}
parent()
这里调用栈的顺序:全局执行上下文--parent函数执行上下文--child函数执行上下文
(2)创建执行上下文
也叫做当前的执行环境,创建过程中,主要是做了下面三件事:
1、创建变量对象(variable object,简称VO)
2、创建作用域链(scope chain)
作用域链由当前执行环境的变量对象(未进入到执行阶段前)与上层环境的一系列活动对象(AO)组成,保证了当前执行环境对符合访问权限的变量和函数有序访问。
3、确定this的指向(先忽略)
可参考this指向问题juejin.cn/post/699872…
VO(变量对象)创建过程:
-
创建arguments对象,检查当前上下文的参数,建立该对象的属性与属性值,仅在函数环境(非箭头函数)中进行的,全局环境没有此过程。
-
检查当前上下文的函数声明,按照代码顺序查找,将找到的函数提前声明,
- 如果当前上下文的变量对象没有该函数名属性,则以函数名新建一个属性,属性值则指向该函数所在堆内存地址引用
- 如果存在,则会被新的引用覆盖掉。
-
检查当前上下文的变量声明,按照代码顺序查找,将找到的变量提前声明
- 如果当前上下文的变量对象没有变量名属性,则新建一个属性,属性值为undefined;
- 如果存在,则忽略该变量声明。
练手
function fun(m,n){
var name = 'hzy';
function execution(){
console.log(name)
}
}
fun(2,3)执行
创建函数fun的执行上下文
funEC = {
VO: {//变量对象
arguments: {//arguments对象
m: undefined,
n: undefined,
length: 2
},
//execution函数
execution: <execution reference>,
//函数内变量
name: undefined
},
//作用域链
scopeChain:[VO(execution), AO(fun), AO(global)],
//this指向
this: window
}
3、执行阶段
执行阶段另开出新文章详细分析,主要介绍js执行阶段中的同步任务执行和异步任务执行机制(事件循环(Event Loop) )
前面问题解决
现在返回看一下
VO: {//变量对象
arguments: {//arguments对象
a: undefined,'function a(){}',
c: undefined,
},
//函数内变量
d:undefined,
b:undefined,'function () {}',
}
打印顺序:function a(){}(函数覆盖)---123--function c(){}(函数覆盖)--undefined--undefined--function(){}(变量声明) ---function c(){}(函数覆盖)
总结
觉得写得好的,对你有帮助的,可以分享给身边人,知识越分享越多,千万不要吝啬呀
后续更新前端其它知识总结,请关注我,整理好,分享给你们,我们一起学前端