栈内存 EcStack (Execution Context Stack)
- 浏览器会在计算机中的内存中分配一块内存,专门用来’供代码执行’的=> 栈内存 EcStack (Execution Context Stack) 执行环境栈
- 供代码执行
- 存储基本数据类型(变量/堆的引用地址)
全局对象 GO(Global Object)
- 全局对象 GO)Global Object)是一个堆内存(存储的都是浏览器内置的API属性方法),在浏览器中会让window执行GO window指向GO (存放属性方法)
浏览器把内置的一些属方法到一个单独的内存中 堆内存(heap)
任何开辟的内存都有一个16进制的内存地址,方便后期找到这个内存
js中的执行上下文 EC(Execution Context)
- EC(Execution Context)执行上下文:代码自己的执行所在的环境
- 全局的执行上下文 EC(G)
- 函数的代码都会在一个单独私有的执行上下文中处理
- 块级的执行上下文
变量对象 VO(Varibale Object)
- 变量对象:在当前的上下文中,用来存放创建的变量对象和值的的地方(每个执行上下文中都会有一个自己的变量对象,函数的私有上下文中叫做AO(Activation Object)活动对象,但是也是变量对象)
- VO(G)全局变量对象:全局上下文中用来存储全局变量的空间,它不是GO=>只不过某些情况下VO(G)中的东西会和GO重的东西有所关联而已"映射机制"
活动对象 也是变量对象(私有) AO(Activation Object)
- 函数进栈执行时形成一个全新的私有的上下文EC(FN(函数))供代码执行
- AO是VO的一个分支,都是变量对象,AO是活动对象,函数中的变量对象都称为AO(FN(函数))私有变量对象
代码在执行的时候,形成的全局上下文,进入到栈内存中执行,简称‘进栈’,在执行完成代码后,可能会(没有被其他的上下文使用或占用)把形成的上下文出栈释放‘出栈’。栈的特点是先进后出
变量创建的方式
- 创建一个值或对象(堆内存)
- 基础数据类型值都是直接存储到栈内存的
- 引用数据类型值是先开辟一个堆内存,把键值对存储在堆内存中,最后把地址放到栈中的提供的变量关联使用的
- 所有的赋值操作都是指针的关联指向
- 创建一个变量
- 让变量和值关联在一起
函数
- 函数也是一个堆,函数体中的代码当作字符串存储到堆中‘代码字符串’,函数不执行,函数没啥用
- 函数也是对象,他有自己的键值对 name lenght(形参个数) prototype proto 等
- 创建函数的时候,就定义了函数的作用域 => 当前创建的函数所在的上下文(当前函数的作用域)[[scope]]:EC(当前函数作用域)(默认EC(G))
- 函数执行的目的? 让之前存储在堆中的代码字符串执行=>代码执行就要有自己的执行环境
- 形成一个全新的私有的上下文EC(FN(函数))供代码执行(进栈执行)
- 把全局上下文放到栈的底部(压缩栈)
- 新进来的上下文放到栈的顶部(置顶)
- 创建私有变量对象(AO(FN(函数名))
- 初始化作用域链(scoppeChain):<EC(FN(函数名))自己所在的上下文,EC(G)创建函数时的作用域(上级上下文)>
- 初始化this指向
- 初始化实参集合:arguments
- 形参赋值:在当前上下文中声明一个变量,把传递的实参赋值给它
- 函数的形参也是存放在自己的上下文中的私有变量对象中
- 变量提升
- 代码执行
- 把之前创建函数,在堆内存中存储的‘代码字符串’拿出来,变成一行行代码的执行
- 代码执行时声明的变量也是私有变量
- 在私有上下文代码执行的时候,遇到一个变量,我们首先看是否为自己的私有变量(在自己的变量对象EC(FN(函数名))中没有),如果是私有的(变量提升),则操作都是自己的,不是私有的,按照作用域链找上级上下文中的… 一直找到全局上下文为止。这就是作用域链查找机制
- 上下文中的代码执行完毕,如果没有被占用或者被上级作用域使用,就会出栈释放
- 形成一个全新的私有的上下文EC(FN(函数))供代码执行(进栈执行)
引用相同的堆内存地址(对象),如果一方改了对象里面的值,因为是地址,关联的都是同一个堆相互影响
var obj = {
name:'哩哩啦啦'
fn: (function (x){
return x+10
})(obj.name)
}
console.log(obj.fn) // 直接报错 在语法分析.预编译阶段就报错了,先创建值,在创建变量去关联,所以在fn的值自执行时,obj是没有声明的(undefined.name),所以报错
执行环境栈
- js之所以能够在浏览器中运行,是因为浏览器给js提供了一个执行环境=> 栈内存(Stack)
- js中存在多种作用域(全局、函数私有的、块级私有的)代码执行之前,首先会形成自己的执行上下文、然后把上下文进栈(全局上下文压缩到栈的底部,新的上下文在顶部)、进栈后、在当前上下文中再依次执行代码
- 全局执行上下文( EC(G) )
- 私有上下文 ( EC(NAME) )
- 作用域和执行上下文的关系,可以理解为:执行上下文是对应作用域中的代码执行环境
- 每一个执行上下文中一定有一个空间用存储创建的变量对象
- 一个页面只有一个VO(G)
function fn(){}
// 类似于
var fn = function(){} // 函数表达式 把一个函数作为值赋值给一个变量或者其它的事物