浅析JS在浏览器中的运行机制

前言 ---了解JS在浏览器中的运行机制,可以帮助我们在大脑里执行JS代码🤓

我们在面试中,经常碰到这样的JS面试题,声明了几个变量,经过一个函数执行后,问我们输出结果是什么?如果我们不是很清楚JS在浏览器中的运行机制,那么此类的面试题就基本上GG了~😫

最近看到这样的一道JS面试题,引发了我的思考:🤓

var x =[12,23];
function fn(y){
    y[0] = 100;
    y=[100];
    y[1]=200;
console.log(y);
}
fn(x);
console.log(x);

如果你能在10秒内给出正确答案,那么大佬🙃,打扰了~ 出口在右手边左转,......🙃🙃🙃

正文

如果你没有清晰的思路快速地给出答案,那么看完这篇文章,再也不用怕此类的面试题,分分钟钟搞定,绝不加班~

接下来 我会通过画图的方式一步一步解析JS运行一个流程:

在画图之前,我们先来了解一下接下来我们会用到的名词概念,以便我们在后面结合图形的方式能够更好地理解。

执行环境栈 ECStack (Execution Context Stack)

如图所示:浏览器提供一个供代码执行的环境=> 执行环境栈ECStack:

它的作用:

1、提供代码执行环境(ECG 全局执行上下文)

2、存储基本数据类型值、变量、堆的引用地址(VOG 全局变量对象)

全局执行上下文 ECG(Excution context Global)

JS中存在多种作用域(全局、函数私有的、块级私有的),代码执行之前,首先会形成自己的执行上下文,然后会把上下文进栈,进栈后,在当前上下文中在去依次执行代码。

VOG 全局变量对象 与GO不同

用来存储基本数据类型值、变量、堆的引用地址

全局对象GO (Global Object)

它是一个堆内存(Heap),在浏览器中存储的是浏览器内置的API属性方法,让window指向它。

浏览器会把内置的一些属性方法放到一块单独的内存中(堆内存 Heap)

任何内存都有内存地址,内存地址是16进制的,假设内存地址是 AAABBB000

我们平常经常使用的函数方法就是放在这个堆内存中,如下所示:

parseInt:function...

isNaN:function...

浏览器会让window 指向这个 GO,eg:parseInt("10") 实际上调用了window.parseInt("10")

=================================================

我们先看一个赋值操作 var a=12;

这一步是如何操作的

1、创建一个值

2、创建一个变量

3、让变量和值关联在一起

基本类型:基本类型的值都是直接放到内存中。

引用类型:先开辟一个堆内存,把值放到堆内存中,把地址放在栈内存中供变量使用。

1、创建一个堆内存

2、把键值对存放到堆内存中

3、把堆内存的地址放到栈中,供变量调用

var b ={};

b.x 基于内存地址 找到堆内存,将堆内存中的属性x进行修改

=================================================

🤔进入解题

运行流程 1 🤓

//1、声明一个变量X

a.首先会在内存中开辟一个堆内存用来存储值 [12,23]

b.在VOG中创建一个变量X,存放值[12,23]的内存地址

c.将变量X与内存地址建立映射关系

运行流程 2🤓🤓

//2、声明一个函数fn

a.新开一块内存空间,用来存储我们创建的函数,创建函数的时候,相当于把函数体中的代码当做字符串存储到堆中

b.在VOG中创建一个变量fn和函数fn的地址AAAFFF111

c.变量fn与内存地址AAAFFF111建立映射关系

注意: 创建函数的时候,就定义了函数的作用域=>当前创建函数所在的上下文,fn的作用域是全局上下文,因为它是在全局环境中创建的

运行流程 3🤓🤓🤓

//3、执行函数fn

a、执行函数fn,把全局变量x的值作为实参传递给函数的形参

b、形成一个全新的私有执行上下文

c、初始化作用域链(scopeChain):<EC(fn)-私有上下文,EC(G)-全局上下文>,作用域链作用:后面私有上下文代码执行的时候,遇到一个变量,我们首先看是否为自己的私有变量(在自己的变量对象中),是私有的,则操作私有变量,如果私有变量中不存在,则按照作用域链向上级上下文中查找,一直找到全局上下文。 d、初始化this指向:window e、初始化实参集合:arguments f、执行函数中的代码

y[0]=100;//由于形参y指向的是变量x的地址AAAFFF000,所以会将地址AAAFFF000中的12改为100

y=[100];//数组[100]会开辟一个新的内存堆BBBFFF000用来存放值100

y[1]=200;//在内存堆BBBFFFF000存放值200

console.log(y);//y指向的是内存堆BBBFFF000,所以输出是 [100,200]

运行流程 4

输出变量x console.log(x);//由图可知输出的是 内存堆AAAFFF000中的值 [100,23]

AO活动对象

注解: AO活动对象,函数中的变量对象都称为AO 在当前的上下文中,用来存放创建的变量和值得地方,每一个执行上下文中都会有一个自己变量对象,函数中执行上下文中的变量对象叫AO(Activation Object)活动对象

结语

实际JS在浏览器中运行过程远远比这复杂,本人表达能力有限,尽自己的能力把问题简单化,便于通俗易懂,后续有时间会不断优化。