JS底层运行机制之堆(Heap)栈(Stack)
- ECStack(Execution [ˌeksɪˈkjuːʃn] Context Stack)和 EC(Execution Context )
- GO(Global Object)
- VO(Varibale Object)
- 变量赋值的步骤
// obj[‘name’] 获取成员为name的属性值
// obj[name] 把name变量存储的值作为成员获取其属性值
对象的属性名
- 字符串
var obj = {
name: ‘xxx’
}
- Symbol
obj[Symbol(‘AA’)] = 100;
- 数字/布尔/null/undefined等基本数据类型值(用这些值直接处理和基于他们的字符串格式处理结果是一样的)
- 也有人认为属性名除了Symbol只能是字符串格式的
数组对象的属性名是数字0、1。
arr[0]和arr[‘0’] 都是为10,都可以访问arr的第0个位置的元素。
网上有观点:对象的属性名只能是字符串和Symbol,其他的情况除了Symbol都会变成字符串。(老师不同意,我个人同意这个观点。)
javascript中对象的key只能是字符串或者Symbol,用其他类型作为key的时候,会调用该类型的toString方法转成string。
{ [Symbol(‘aaa’)]: 111 } 为什么要加 [], 是因为 Symbol是构造函数, Symbol(‘aaa’) 其实是个表达式,所以要加上 []。
var obj = {
name: 'xxx,
0: 100
}
obj[0]和obj['0']都认为可以访问属性0为100的值
- 对于普通对象来讲,属性名不能是引用数据类型值(比如对象),设置为对象,也会转换为字符串;
ES6中新增Map数据结构,这个结构中可以允许属性名是一个对象;
var obj = {
name: ‘xxx’,
0: 100,
true: 11
};题目一
```javascript //example 1 var a={}, b=’0’, c=0;
a[b]=’web’; // a[‘0’] = ‘web’ a[c]=’开发’; // a[0] = ‘开发’ console.log(a[b]); // a[‘0’] = ‘开发’
//example 2
var a={}, b=Symbol(‘1’), c=Symbol(‘1’); // b!==c Symbol(‘1’)唯一值
a[b]=’web’;
a[c]=’开发’;
console.log(a[b]); // ‘web’
//example 3
var a={}, b={n:’1’}, c={m:’2’};
a[b]=’web’; //a[“[object Object ]”] = ‘web’
a[c]=’开发’; //a[“[object Object]”] = ‘开发’
console.log(a[b]); // a[“[object Object]”] = ‘开发’
<a name="VBbU5"></a>
#### 题目二
```javascript
var a = {n: 1};
var b = a;
a.x = a = {n:2};
console.log(a.x)
console.log(b)
1)a = {n:1}
{n:1} 开辟一块堆内存 存储 n:1 ,堆内存地址AAAFFF000,并且地址赋值给a
2)b ={n:1}
把堆内存的地址AAAFFF000赋值给b
此时a和b都指向堆内存的地址AAAFFF000,注意存堆内存地址AAAFFF000是个栈内存
3)然后关于连等于,因为a.x的优先级比较高,所以先做a.x = {n:2}的访问成员赋值,
然后再做a= {n: 2}的创建新的地址赋值,新的堆内存的地址为AAAFFF111。
a.x = {n:2}后,a和b共同指向的堆内存(AAAFFF000)里变成了{n: 1, x: {n:2}}
a= {n: 2} 后,a被指向了一个新的堆(AAAFFF111),里面是{n:2}
4) 因此a里面没有x属性,访问当前对象的某个成员x,成员不存在,不会报错,只会undefined。a.x 为undefined。
b为{n: 1, x: {n:2}}
执行环境栈 Execution Context Stack:浏览器提供代码执行的一个环境。
EC:执行上下文
EC(G):全局执行上下文
**var a={...}**
先创建一个值;声明一个变量;让变量和值关联在一起,做一个指针指向。
var a = b = 12 有俩种表示方法:1)b=12;var a=12; 2) b=12;var a=b;
JS运算符优先级:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
eval: 把字符串变为JS表达式。eval(“1+1”) = 2;
eval、setTimeout、isNaN和parseInt等等都是浏览器内置的东西。
在浏览器端是window,在node端是global。
console.log其实是window.console.log,window可以省略。
浏览器最开始加载代码的时候,不仅提供了一个栈内存供代码执行,而且还默认开辟了一个堆内存(GO),存储一些内置的属性和方法。
GO(Global Object)全局对象
全局对象!==全局变量对象
VO(G)是全局变量对象,用来存放存储全局声明的变量的,当然也包含浏览器默认创建的全局变量的,叫window。
GO是全局对象,浏览器默认提供的内置的属性和方法, 都存在堆里面。最后window指向堆,或者说堆内存地址赋值给window了,可以通过window调用了。
VO中有一个叫做window的变量,变量值是GO。但是不能说VO包含GO,VO和GO只是一个指针关联关系,俩者是平行关系。
浏览器默认创建的一个全局变量window,指针指向堆内存(GO)。
在VO上创建的变量会自动在window上也关联一份。
在全局上下文中,基于”var/function”声明的全局变量,也会给GO(window)中新增一个对应的私有属性,并且和全局的变量有”映射机制”:一个修改,另外一个也会跟着修改。
var a =10; // 1.声明一个全局变量a=10 2.给window新增一个私有属性window.a = 10
console.log(window.a); // 10 直接访问对象的成员
console.log(a) // 首先看a是否是全局变量,如果是按照全局变量处理。如果不是全局变量,再看下是否为window的一个属性。如果也不是window的属性则报错: a is not defined
window.a = 20 // "映射机制"全局变量a=20
console.log(a) // 20
// 基于”let/const“声明的全局变量和window没有关系
let a = 10; // 全局变量a
console.log(a); // 10
console.log(window.a); // undefined
// 在全局上下文中
a = 10; // 不是全局变量,window.a = 10, 相当于省略了window(前提:确定之前没有声明过)