高级js学习(1)typeof检测机制+栈堆内存

1 数据类型

  • ECMAScipt是基于对象的:在ECMAScript中,对象是0个或者多个属性的集合,每个属性具有决定每个属性的“属性”,当属性的可写属性被设置为false的时候,执行ECMAScirpt代码为其分配不同的值都将失败。
  • 属性是容纳其他对象,基本值或者函数的容器。原始值是以下内置类型之一的成员,undefined null boolean number string symbol。对象是内置类型对象的成员,函数是可调用对象,通过属性与对象关联的函数称为方法。
  • 原始类型
    number null undefined string boolean symbol bigint
  • 对象类型
    标准普通对象 Object
    标准特殊对象 Array RegExp Date Math Error…
    非标准特殊对象 Number String Boolean…
    可调用/执行对象 function

类型检测

  • typeof
  • instanceof (较少用)
  • constructor(较少用)
  • Object.prototype.toString.call
  • Array.isArray
  • IsNaN

typeof底层机制

我们知道typeof对于对象的检测很模糊,如
在这里插入图片描述
typeof除了对函数能够正确标识,对其他的对象检测都比较模糊。且对null的判断也是Object

  • 因为typeof直接根据变量值得内存标识符进行判断。
    typeof 一般用来判断 number、string、boolean、undefined、object、function、symbol这七种类型。
    而js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:
    000:对象 010:浮点数 100:字符串 110:布尔 1:整数
    那null为什么也是object呢?因为null的所有机器码均为0,所以typeof检测的时候也认为是对象了。

js底层存储机制 堆(Heap) 栈(Stack)内存

通过浏览器去加载页面的时候,会从计算机的内存条中分配出两块内存(堆栈内存)。

  • Stack内存(ECStack执行环境z栈)
    作用: 1 供代码执行; 2 存放声明的变量; 3 存放原始值类型的值。

  • Heap堆内存
    作用:1 存放对象类型的值。
    浏览器提供了很多的api,比如setTimeout, alert等等,在开辟堆内存的时候会开辟一块空间,专门放这些内置的属性和方法。
    而这块专门存放这些内置属性方法的空间有个专用名词,GO(global object),全局对象。

开辟空间后准备执行代码了

  • 当开辟完这两块空间后,就会开始开始执行代码。那浏览器是如何判断哪些代码是全局上下文的,哪些代码是函数里的上下文的。
  • 最开始,会执行全局下的代码,形成一个全局的执行上下文EC(G),Exectution Context,g表示是全局的上下文。然后代码开始进栈执行(代码执行都在栈里执行)
  • 代码进栈,执行之前,会在每一个上下文中创建一个VO,变量对象。全局上下文就创建一个VO(g),全局变量对象。记住,是每一个执行上下文中都有一个变量对象,是用来存放当前上下文中声明的变量。
  • 浏览器默认会在VO(g)中,创建一个window变量,这个变量的值是栈内存中的GO全局对象的地址,所以我们才可以通过window.xxx去调用内置的api啥的。

接下来开始执行代码了

  • 当遇到如let a =xx,首先第一步是先创建值,原始值是直接存储到栈内存中,对象值需要在堆内存中开辟出一块小空间,存放对象的键值对,将空间的地址(16进制),最后把该地址放到栈内存中,供变量使用。

  • 第二步就是声明变量了(declare),把声明的变量存放到当前上下文的vo(变量对象)中。

  • 第三步就是赋值操作了(defined),让变量的值与对应的值关联在一起(指针指向的过程)
    在这里插入图片描述

  • 再遇到let b = a的时候,在全局vo中又创建了一个变量b,再将b与a的值也关联在一起。当遇到b=13再赋值的时候,b就会跟13重新关联在一起。一个变量只能关联一个值,一个值可以有多个变量关联。此时b的值就是13,而a的值还是12,他们互不影响,所以原始值都是按值操作(即值是不会改变的)。在这里插入图片描述

  • 上面的是原始值的一些操作,接着看对象的操作。如果遇到
    let a = {n: 12},此时还是先创建值,因为是对象,所以会在对象堆地址中,开辟一块空间,地址名为0x001,里面放着键值对,n:12。再将地址名0x001放到栈内存中,供变量关联。然后再在vo(g)中创建a,将a与该地址关联起来。

  • 接着遇到 let b = a,先从作用域中找a的值,然后将b与a关联的值,关联起来。

  • 接着 b[‘n’] = 14,这时候,会先去找b是谁,发现是一个堆地址后,就会基于地址0x001找到堆的空间,再把空间中,n的值修改为14。

  • 而这时候,a的值也是这个地址,所以通过a访问n的时候也会发现值被改变了。所以对象类型的值是按照堆内存空间的引用地址来操作(不是直接操作值),所以也叫引用数据类型,这也是与原始值操作的本质不同。

总结

  • 浏览器执行代码之前会开辟两块空间,堆内存和栈内存,栈内存是用来执行代码的,存放变量,存放原始值。而堆内存是用来存放对象的值。
  • 堆内存在开辟出来后会开辟一块空间叫做GO,全局变量对象,顾名思义就是存放着setTimeout这是全局api的。
  • 然后执行全局下的代码,先形成全局上下文EC(G),然后进栈执行,每个上下文都有一个变量对象,VO,用来存放当前上下文的变量。所以浏览器会在VO(G)全局变量对象中创建一个变量window,将他的值与GO,全局变量对象关联起来,所以我们可以通过window.xxx去调用内置api。
  • 遇到赋值操作的时候,原始值会在栈中创建,对象值会在堆内存中开辟一块空间,存放键值对,再将空间的地址存放到栈之中,供变量使用。
  • 然后再创建变量,会在当前山下文的vo中创建一个变量,将变量与值关联指针起来。
  • 操作变量的值的时候,如果是原始值,那么会将该变量与新的值关联起来,不会影响旧的值,所以原始值就是按值操作的。如果是对象,比如a[‘v’] =14,这时候就会拿到a的值,发现是堆地址后再通过该地址找到内存空间,然后去修改v的值,此时如果有别的变量比如b也是关联该地址,那么b.v也会呗影响,因为他们指向的是同一个空间。所以对象值是按引用地址操作的。
VO(G)与GO(全局变量对象与全局对象)
  • 刚才我们举例子没有通过var,是因为在全局上下文中,var声明的变量是存放在GO中
  • 全局上下文中,是全局,基于var和function声明的变量,不是存放到VO(G)的,而是在存放到GO中的,而window又与GO关联,所以以前那些全局上下文中执行var a = 1,然后可以通过window.a去获取值的原理也是这样来的。
  • 而基于let const calss声明的变量都是存放到VO(G)的,和GO没啥关系,而没有声明的,比如 a = 1,也是直接存放到GO中的。
  • 还有一点,在全局上下文中使用一个变量,如console.log(a),这个a首先会去VO(G)中查找,如果没有再去GO查找,再没有就报错。
变量提升

当做完上述的事情后,在执行代码前就会变量提升,不会es6后基本不会了。

  • 变量提升:在当前上下文中,代码执行之前,浏览器会将所有带var和function关键字的进行提前声明或者定义。
  • 区别:用var声明的变量只会提前声明。用function声明的函数会提前声明+定义(赋值)
    在这里插入图片描述
    在这里插入图片描述

关于堆栈内存的面试题

var a = {
    
     n: 1}
        var b = a;
        a.x = a = {
    
    
            n: 2
        }
        console.log(a.x)
        console.log(b)
  • 我们假设上面的{n:1}的地址就是0x001,此时a,b均在GO中,值为0x001

在这里插入图片描述

  • 这里比较复杂的就是a.x =a ={n: 2}首先还是先创建值,就在栈内存的地址下创建了{n:2} 0x002,则变成a.x = a = 0x002,
  • 正常的顺序是从右到左(优先级),如a = 0x002,a.x=0x002,如果是var a = b =1 ,就是先b = 1; var a = 1;
  • 但是a.x = a = 0x002,a.x是成员访问,优先级更高,所以应该是a.x = 0x002, 再a = 0x002,也就是a.x = {n:2}, a = {n:2},正确顺序应该是这样。
  • 就变成了在这里插入图片描述
    此时a指向了0x002。即a = {n: 2}, b还是原来的地址,就是 b = {n: 1, x:{n: 2}}
    结果如图
    在这里插入图片描述
    这道题涉及堆栈内存,以及优先级访问顺序。

Guess you like

Origin blog.csdn.net/lin_fightin/article/details/120341320