前言 ---了解
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在浏览器中运行过程远远比这复杂,本人表达能力有限,尽自己的能力把问题简单化,便于通俗易懂,后续有时间会不断优化。