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;
image.png

  • 数字/布尔/null/undefined等基本数据类型值(用这些值直接处理和基于他们的字符串格式处理结果是一样的)
  • 也有人认为属性名除了Symbol只能是字符串格式的image.png

数组对象的属性名是数字0、1。
arr[0]和arr[‘0’] 都是为10,都可以访问arr的第0个位置的元素。
网上有观点:对象的属性名只能是字符串和Symbol,其他的情况除了Symbol都会变成字符串。(老师不同意,我个人同意这个观点。)
javascript中对象的key只能是字符串或者Symbol,用其他类型作为key的时候,会调用该类型的toString方法转成string。
{ [Symbol(‘aaa’)]: 111 } 为什么要加 [], 是因为 Symbol是构造函数, Symbol(‘aaa’) 其实是个表达式,所以要加上 []。
image.png

  1. var obj = {
  2. name: 'xxx,
  3. 0: 100
  4. }
  5. obj[0]和obj['0']都认为可以访问属性0100的值
  • 对于普通对象来讲,属性名不能是引用数据类型值(比如对象),设置为对象,也会转换为字符串;
  • 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]”] = ‘开发’

  1. <a name="VBbU5"></a>
  2. #### 题目二
  3. ```javascript
  4. var a = {n: 1};
  5. var b = a;
  6. a.x = a = {n:2};
  7. console.log(a.x)
  8. console.log(b)


1.png
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
image.png

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)中新增一个对应的私有属性,并且和全局的变量有”映射机制”:一个修改,另外一个也会跟着修改。

  1. var a =10; // 1.声明一个全局变量a=10 2.给window新增一个私有属性window.a = 10
  2. console.log(window.a); // 10 直接访问对象的成员
  3. console.log(a) // 首先看a是否是全局变量,如果是按照全局变量处理。如果不是全局变量,再看下是否为window的一个属性。如果也不是window的属性则报错: a is not defined
  4. window.a = 20 // "映射机制"全局变量a=20
  5. console.log(a) // 20
  6. // 基于”let/const“声明的全局变量和window没有关系
  7. let a = 10; // 全局变量a
  8. console.log(a); // 10
  9. console.log(window.a); // undefined
  10. // 在全局上下文中
  11. a = 10; // 不是全局变量,window.a = 10, 相当于省略了window(前提:确定之前没有声明过)