JS之所以能够在浏览器中运行,是因为浏览器给JS提供了执行的环境 => 栈内存(Stack)(其实就是在电脑现有的内存当中分配出一点内存,专门用来供代码运行)
- 执行环境栈:浏览器会在计算机内存中分配一块内存,专门用来供代码执行叫做栈内存 ECStack(Execution Context Stack)也叫做执行环境栈(每打开一个网页都会形成一个全新的执行环境栈)
- 此外,浏览器中会提供很多供我们调用的属性和方法(isNaN(),parseInt()等),之所以能用这些方法,是因为浏览器会把所有供我们调用的方法放到到 全局对象GO(Global Object)中
- 全局对象GO(Global Object):浏览器把内置的一些属性方法放到一个单独的空间或者内存当中,这个内存叫做 堆内存(Heap)中
- 任何开辟的内存都16进制的地址,方便后期找到这个内存
总结:
- 浏览器一打开一个页面,会有一个供代码执行的环境,叫执行环境栈(ECStack)
- 内置一些属性方法,会存在堆内存当中,我们把这个堆内存叫做全局对象GO
- 浏览器端会让window指向这个GO,所以浏览器端windown指向的就是全局对象
先画两个框,方便理解
- 栈内存:提供代码执行的环境
- 堆内存:存放东西(属性和方法)
代码执行的环境已经有了,可以开始代码执行了
- 每一块代码都有自己执行的一个环境
- 专业名词叫作:EC(Excution Context)执行上下文(代码自己执行的所在环境)
- 全局执行上下文EC(G)
- 函数中的代码都会在一个单独的私有的执行上下文中处理
- 块级的执行上下文(es6中会有)
- 全局代码执行会有一个全局执行上下文EC(G)
6. 出栈:(私有的代码执行完(函数执行的代码),可能会把形成的上下文出栈释放,全局的上下文会在页面关闭时释放)栈结构特点:先进后出
7. 为什么要出栈?栈内存中越来越多的话,空间就会越来越大,占用的计算机内存就会越来越多,电脑就会变卡顿
var a = 12;
var b = a;
b = 13
console.log(a)
-------------
var a = {n: 12};
var b = a;
b['n'] = 13;
console.og(a.n)
---------------
var a = {n: 12};
var b = a;
b = {n: 13};
console.log(a.n)
- 代码自上而下执行,创建的变量和值 存放在一个地方叫做:变量对象当中VO(Varible Object)。换句话讲,就是在当前的上下文中,用来存放创建变量和值的地方(和堆不同的是:只是在栈内存中的执行上下文的环境中又单独开辟的一个小空间,堆是单独开辟的内存)
- 每个只想上下文中都会有一个自己的变量对象
- 函数私有上下文当中叫做 :AO(Active Object),是VO的一个分支
- 代码正式执行,先以第一段代码为例
var a = 12;
// 这一步是如何操作的?
// 1,创建一个值; 基本类型值直接存储到栈内存中,引用数据类型是先开辟一个堆内存,把东西存进去,最后把地址放到栈里边,供变量关联使用
// 2,创建一个变量;
// 3,让变量和值关联
var b = a;// 等号右侧是一个变量,没有新值,b关联到a的指针指向
b = 13;// 先创建一个新值13,让变量b指向13.一个变量只能关联一个值。
console.log(a) // 12
console.log(b) // 13
完整图
var a = {n: 12};
var b = a;
b['n'] = 13;
console.og(a.n)
- 执行环境栈
- windown = Go
- 全局执行上下文EC(G)进栈
- 全局变量对象VO(G):存储变量和值
- 代码正式执行前的其他操作....
- 代码执行
- 创建一个值:{n:12},因为引用类型,所以创建一个16进制地址为AAAFFF000的堆来存储
- 创建变量a
- a与AAAFFF000关联
- 创建变量b,b = a,b指向AAAFFF000
- b['n'] = 13;基于地址AAAFFF000,找到堆内存将n的值改为13
- a与b是同一个地址,所以a指向的也是修改后的AAAFFF000,s输出a.n =》 13
- 以第三段代码为例
var a = {n: 12};
var b = a;
b = {n: 13};
console.log(a.n)
重复第二段代码时的步骤
- 执行环境栈
- ....
- 代码执行
- 前两行代码和第二段一样
- 第三行代码:b = {n: 13}
- 此时{n: 13} 是新的对象,新的堆,所以创建一个地址为AAAFFF111de 新堆
- b 指向新堆
- 此时a和b 指向不同的堆内存,所以怎么操作都互不影响
- console.log(a.n) 结果是12
测试题:
var obj = {
name: '张',
fn: (function(x) {
return x + 10;
})(obj.name) // 在给fn赋值的时候,是把自治性函数的返回结果赋值给fn
}
console.log(obj.fn) // Uncaught TypeError: Cannot read property 'name' of undefined
结果是:报错
- 已知 赋值操作要分三步
- 创建值
- obj是个对象,所以开辟一个堆内存AAAFFF000
- 存储键值对
- name: '张'
- fn: 自治性函数执行,需要把obj.name 的值当作实参传进来。 此时还是在创建值阶段,还没创建obj呢,obj是undefined
- undefined是没有name属性的,所以报错,代码不再执行。