javaScript学习第6天(程序执行过程 堆与栈)

程序执行过程(重要)

堆和栈

堆栈本身是是数据结构。堆(链表结构)、栈(栈结构)。

程序在运行的时候内存按照逻辑分为了堆内存和栈内存。

  • 栈:栈结构中开辟的内存比较小。速度快,操作系统会自动回收内存。

    特点:先进后出。

  • 堆:开辟的内存通常比较大,速度比较慢。

    特点:先进先出

JS中已经封装了垃圾回收机制。

执行环境

每个运行环境我们通常也称为执行上下文。

JavaScript中运行环境分为两种:

  • Global,全局的。JavaScript代码开始运行的时候就默认存在的执行环境。
  • Function,函数执行环境。进入一个javaScript函数的运行环境(函数调用时才会进入);

代码在执行时开辟一段栈空间来说明代码的执行顺序,这个栈我们叫执行栈

  1. 当JavaScript代码执行时会将全局执行上下文压入到栈底,当执行到函数执行上下文,也会将函数执行上下文压入到栈底。
  2. 函数执行完成之后将函数执行上下文弹出并且销毁(和执行环境相关的一系列内容都会被销毁)。
  3. 直到所有代码执行完成才将全局执行上下文销毁。
执行环境的阶段

每个执行环境分为两个阶段:

  • 创建阶段(做准备工作的)
    • 全局执行环境:一上来就进入了创建阶段。
    • 函数执行环境:当函数被调用,但是开始执行函数内部代码之前。
  • 代码执行阶段(真正的解释、执行代码)
作用域及作用域链
  • 什么是作用域?

    作用域:变量起作用的区域范围。

  • 作用域的作用?

    隔离变量(函数外部定义的和函数内部定义的同名变量没有关系)

  • 作用域的确定时机?

    作用域是在进入到全局执行环境或函数执行环境时确定好的。

  • 作用域种类?

    在ES5中作用域只分为两种,全局作用域和函数作用域(局部作用域)。ES6里面新加了一个块级作用域。

​ 一执行javascript就进入了全局执行环境就有了全局作用域,执行某个函数时进入到函数执行环境就有了函数作用域(局部作用域);

​ 一个执行环境对应着一个作用域。

同一个函数多次调用会产生不同的执行环境,每次调用都会产生一个。

  • 全局变量和局部变量

    • 全局变量:定义在全局环境中的就是全局变量(函数外部定义的,全局作用域)。
    • 局部变量:定义在局部环境中就是局部变量(函数内部定义的,函数作用域)。

    局部变量:只能在自己的作用域中使用,只能在函数内部使用,外部不能用。

    全局变量:在整个程序所有的地方都会起作用(整个程序当中任何地方都可以操作这个全局变量)

    全局变量可以被函数内部进行操作,但是全局当中没有办法操作局部变量(如果真的要操作就需要用到后面讲的闭包)。

  • 作用域链

    • 函数内部是可以嵌套函数的。

      function test(){
          function test1(){
              console.log('test1');
          }
          test1();
          console.log('test');
      }
      test();
      

    作用域链:作用域是变量起作用的范围,作用域链是用来找变量的一系列的过程。

​ 一个函数在定义时会自动生成一个[[scope]]的属性([[]]都是不能直接通过代码访问的),[[scope]]属性中存储的是函数定义时作用域的层级。

在这里插入图片描述

作用域链是函数执行时创建的,作用域链由:当前执行的函数作用域 + [[scope]]属性中的作用域组成的。

执行环境如果被销毁的话,其对应的作用域链不会被保留,会被销毁。

函数当前执行的作用域是作用域链的顶端,全局作用域是作用域链的最后端。

  • 总结:
    1. 每个执行环境都会有自己独立的作用域链。
    2. 作用域链由当前的执行环境的作用域和[[scope]]属性组成。在调用时才形成。
      1. 函数调用时形成了执行环境、作用域。
      2. [[scope]]属性:函数定义时就已经生成了,函数即使不调用也会有这个属性。其中存储的是包含定义它时的各个层级的作用域。
内存中的数据存储

变量的值如果是基本类型(String、Boolean、Number、Undefined、null),会在栈内存开辟一段空间存储标识符,然后将基本类型的值也存储在栈内存中和标识符对应起来。

引用类型的值存储在堆内存里,存储引用类型的时候会给堆内存一个地址。但是标识符还是存储在栈内存中,为了能够让标识符和真正的数据对应起来,栈中存储的值是引用类型的地址。

内存地址使用十六进制0x开头表示。

查找变量是和执行环境有关系(作用域链)和堆没有绝对的关系,堆只是也来存储对象类型的数据的。

程序开始到结束执行了什么:

  1. 程序一开始就碰见了全局环境,首先会创建全局环境并且进行压栈,全局代码执行的时候依赖的是全局环境当中的东西。

    全局变量如果是基本类型,那么这个值直接在栈当中,如果这个变量是对象(函数、数组),那么函数和数组是要在堆结构中开辟自己的空间专门存储数据的。然后把堆里面这块空间的地址,给栈当中对应变量进行保存(他们两个是对应的)

  2. 当程序执行碰到了函数调用(函数比较特殊,因为函数可以执行),函数执行时候也要有自己的环境,函数执行也是创建自己的函数环境进行压栈。(函数执行环境一定是压在全局环境之上的。)

    局部变量,是在函数环境中存在的,只有函数执行,局部变量才会出现。函数执行完成之后函数环境要弹出栈(函数执行环境要将对应的一系列东西销毁,释放内存),局部变量也就不存在了。

  3. 当函数调用完成之后,会继续执行全局代码,一直到所有的代码都执行完成,代码程序执行结束,程序结束时,全局环境最后出栈。

变量提升(预解析)

在执行环境的第一步(创建阶段)时,将带var的变量的声明及函数的声明(function abc(){}),放在了作用域中,在执行阶段开始时,代码本身的逻辑和其他逻辑还是在原来的位置。

注意:

  1. 全局执行环境、函数执行环境,每个执行环境都会有一个变量(变量、函数声明)提升的操作。
  2. 函数表达式不会被提升。
  3. 函数名和变量同名。函数声明和变量都会被提升,但是函数会先被提升,然后才是变量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值