面试再探讨:浏览器中js的执行与机制

前言

上回我们深入了解了作用域、作用域链,那么今天我们再次深入探讨一下浏览器中js的执行与机制的底层原理,聊聊调用栈作用域链这一全过程,全局执行上下文函数执行上下文eval执行上下文,这个创建、删除过程又是通过一个什么数据结构完成的呢?

面试题引入

在此之前先给各位安利一款百度最近刚刚开源的插件,vs中或者其他idea类全家桶都能够安装,comate.baidu.com/index.html?... ,你也可以之前通过vs插件搜索baiducomate,真的很智能,你们可以去试试。

ini 复制代码
function bar(params) {
    console.log(myName);
}

function foo(params) {
    var myName = 'Tom'
    bar();
}

var myName = 'Jerry';

foo();

题目很简单,但是需要你真正理解底层的执行过程

变量提升(发生在编译阶段)

在 JavaScript 中,变量提升是指在代码执行之前,变量和函数声明会被提升到当前作用域的顶部。 这意味着即使在声明之前使用变量,也不会导致错误,但此时变量的值是 undefined。 需要注意的是,只有声明会被提升,赋值操作不会被提升。

ini 复制代码
console.log(x); // 输出 undefined 
var x = 5;

那么这个代码事实上长这样

ini 复制代码
var x
console.log(x); 
x = 5;

包含函数的变量提升

javascript 复制代码
console.log(myFunction); // 输出函数定义

function myFunction() {
  console.log("函数被调用");
}

在js引擎的眼中的执行上下文创建过程

之前我们谈过GO(全局作用域对象)、AO对象,那么其实每一个执行上下文中都有一个变量环境和一个词法环境,变量环境中放var的声明变量和函数声明,词法环境中放let和const声明的变量。接下来回到这个面试题引入部分

ini 复制代码
function bar(params) {
    console.log(myName);
}

function foo(params) {
    var myName = 'Tom'
    bar();
}

var myName = 'Jerry';

foo();

分析过程

这些创建的GO\AO对象都存放在哪里呢?

  • 栈结构: 特殊的数组,先进后出
  • 调用栈: js引擎用来追踪函数调用关系的
  • 栈溢出: 调用栈超出内存限制 代码从上往下执行,在全局中首先创建GO对象,也就是全局执行上下文,存放在栈中,放入栈底,全局上下文中有变量环境与词法环境,代码从上往下执行就会发现声明了bar函数和foo函数以及myName变量。图中(全局可执行对象打错了,应该是全局执行上下文!)

紧接着就执行代码,调用foo函数,既然要调用foo函数,首先就需要对foo函数进行预编译,创建AO对象,放入栈中,变量声明首先值为undefined,然后赋值为Tom

紧接着执行调用bar函数,此时需要对bar函数进行预编译,创建AO对象

打印myName,那么在这里就发现了bar执行上下文中没有myName,那么接下来这个属性去哪里找呢?我们都知道,执行上下文中会从词法环境开始找,然后再找变量环境,如果都没有呢?是顺着栈顶向下找吗?答案是否定的。事实上每一个执行上下文中,都存有一个outer属性,这个outer属性的规则是:我的词法作用域(在函数定义时所在的作用域)在哪里,我就指向哪里。那么在bar中,bar的词法作用域存在于全局执行上下文中,那么这个outer就指向全局执行上下文,在自己的bar执行上下文对象中没有找到myName属性,就去全局中找,全局中myName属性值为Jerry,前面的图忘记加上了,在调用foo之前,已经执行过对Myname属性赋值的语句了,这也是一个执行代码的过程

接下来bar函数执行完毕,需要对bar的执行上下文进行释放,弹栈,然后foo执行完毕,进行弹栈,在这我们能够理解,如果不弹栈,见到一个我们就需要创建一个执行上下文对象,长此以往,就会造成栈溢出

小结

本次内容虽然很简单,但是极易出错,知识点都是代码的底层逻辑,理解透彻以后才能在面试时对答如流从容面对。再次多提一下,在执行上下文中的查找过程,是从词法环境查找然后再往变量环境中查找,每一个环境又是一个小的栈结构,也是从栈顶开始向栈底查找,如图所示:

相关推荐
web147862107236 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_748247806 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖10 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案117 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
ThisIsClark21 分钟前
【后端面试总结】MySQL主从复制逻辑的技术介绍
mysql·面试·职场和发展
m0_7482548822 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.34 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营38 分钟前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css