Execution Context Stack
js代码执行的时候,得有一个环境:
Execution Context Stack (执行上下文栈(环境)简称:EC)
等价关系:栈 <=> 作用域 <=> 上下文 <=>执行环境
(在提到这几个词的时候,可以理解为同一个意思,可以等价代换,哪个好理解就用哪个来理解)
-
可执行的全局环境 (全局执行上下文):EC(g)
-
函数执行的环境 (私有上下文):EC(function)
变量对象
存储变量的空间叫做变量对象
-
VO(Varible Object):全局变量对象,存储全局变量,在EC(g)中
-
AO(Active Object):函数中的变量对象,存储函数里面的私有变量,在EC(function)中
当代码执行时,所有的栈依次进行进栈操作
如果代码执行完毕,并且里面的东西没有被占用,就会有一个出栈的操作。
全局对象
GO(Global Object) :浏览器会提供一些方法和属性放到GO中,即内置的方法和属性
让全局的 window 这个变量指向 GO
window 这个全局变量是在 VO 中存放的
而GO 和 VO/AO 没什么关系
此处可以理解为:
GO是一个堆内存,里面存的是键值对,键值对都是内置的方法和属性,然后把这个堆内存的地址给了window,相当于 window 就是这个全局对象
VO 和 GO 的关系
var a = 1;
console.log(window.a);
=> 1
在全局下声明的变量,会和GO有一定的映射关系,就相当于给GO也会添加一个这样的属性。如果一个变量没有声明,经过作用域进行查找,知道EC(g),都没找到,那就是给GO添加这个属性
window是一个特殊的对象,在对window进行成员访问的时候,可以省略 "window.",直接写属性名即可使用里面的方法和属性。
变量的存储
1、多个变量可以指向同一个值,但是一个变量只能对应一个值 (可以多对一,可以一对一,但是不可以一对多)
2、在变量对象中分为变量存储区域和值存储区域,如果值是一个基本数据类型值,则直接存储在值存储区域,让变量指向它;如果值是一个引用数据类型值(对象或函数),则会开辟一个堆内存,用来存放对象的键值对或者函数的代码字符串,并将这个堆内存的空间地址放到值存储区域,让变量指向它。
对象的属性名
1、对象成员访问的时候,属性名字符串里面是数字的, 可以省略引号,像数组的索引那样
let obj={},a="1",b=1;
obj[a]="哈哈";
obj[b]="嘿嘿";
console.log(obj["1"]);
=> "嘿嘿"
2、与第一条同理,可以得出结论:对象的属性名可以是任意的基本数据类型,不能是引用数据类型,如果是引用数据类型,会转化为字符串。但是在处理的时候,除了symbol数据类型以外,各种数据类型和字符串是互通的
let obj={};
obj[true]=1;
obj[null]=10;
obj[undefined]="哈哈";
console.log(obj);
=> {true: 1, null: 10, undefined: "哈哈"}
console.log(obj["true"],obj["null"],obj["undefined"]);
=> 1 10 "哈哈"
let obj ={};
obj[Symbol(10)]=20;
console.log(obj)
=> {Symbol(10): 20}
console.log["Symbol(10)"]
=> undefined
3、对象的属性名如果是symbol数据类型,用for in 遍历对象,是遍历不出来的
let obj ={"name":"LiHua","age":18};
obj[Symbol(10)]=20;
for(let key in obj){
console.log(key);
}
=> name age
(注:此处的key是被遍历对象中的属性名,对象的属性值则是obj[key])