javascript执行机制

 

javascript代码执行流程:代码->编译->执行

  1. 变量提升:指在Javascript代码执行过程中,javascript引擎把变量的声明部分函数声明部分提升到到代码开头的“行为”;变量提升后,会给变量设置默认值,也就是undefined
    1. 解释了javascript语言变量可以先使用后定义的原因
    2. 实际上变量和函数的声明在代码的位置不会改变,而是在编译的时候被放入内存
    3. 一段代码定义了两个相同名字的函数,那么最终生效最后一个,因为后面会覆盖前面的定义
    4. function的创建、初始化、赋值都会被提升
    5. var 的创建和初始化会被提升,赋值不会被提升
    6. let的创建被提升,初始化和赋值不会被提升 (初始化前使用变量会形成一个暂时性死区)
  2. 执行上下文(执行环境):执行代码时候的运行环境
    1. 变量环境对象:存放变量的名称,并且变量初始化为undefined(环境中定义的所有变量和函数都保存在这个对象中)
    2. 词法环境:保存let,const声明的块级作用域变量,内部也是栈结构的形式来处理块
    3. 外部引用outer:指向外部执行上下文(作用域链指针),在声明的时候就指定了
    4. this:每个执行上下文都有一个this
      1. 全局作用域中的this指向window,在严格模式下是undefined
      2. call,apply,bind可以修改当前执行上下文中的this
      3. 对象调用方法this指向该对象
      4. 嵌套函数中的this不会从外层函数继承;可使用箭头函数解决
      5. 箭头函数不会创建自身的执行上下文;所以this取决于他的外部函数
      6. 使用new 构造函数初始化对象原理
        1. 创建一个新的空对象temp
        2. 调用call方法,把构造函数的this指向temp
        3. 执行构造函数,此时构造函数this指向temp,所以构造函数中this指定的属性和函数相当于temp.属性;所以就会为temp创建属性和方法
        4. 最后返回temp
        5. 使用new来创建对象(调用构造函数)时,如果构造函数本身带返回值,那么return的是非对象(数字、字符串、布尔类型等)会忽而略返回值;如果return的是对象,则返回该对象。
  3. 调用栈(call stack):管理执行上下文的执行顺序
    1. 利用栈的先进后出的特点,栈低是最先执行的环境(全局上下文),然后执行到某个函数就该函数的执行上下文进栈,执行完立即出栈
    2. 调用栈有大小,超过一定数目会栈溢出,如使用递归导致的溢出
  4. 作用域:程序中变量定义的区域,该位置决定变量的生命周期;也就是变量和函数的可访问范围
    1. 作用域控制着变量和函数的可见性和生命周期
    2. 全局作用域:变量全局可访问
    3. 函数作用域:函数的内部可访问
    4. 块级作用域:当前块中有效 let、const,在词法环境中的栈结构来管理各个块的执行顺序
    5. 词法作用域:指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它能够预测代码在执行过程中如何查找标识符
      1. 在代码编译的时候就决定了,和函数的调用没关系
    6. 作用域链:作用域查找变量的链条,链条由词法作用域决定的
    7. 变量查找流程:先在当前执行上下文中沿着词法环境栈顶向下查找->变量环境->outer指向的执行上下文的词法环境->变量环境->->->->->直到全局作用域找不到就报错(作用域链
    8. 闭包:在javascript中,根据词法作用域的规则,内部函数可以访问外部函数中声明的变量,当通过一个外部函数返回一个内部函数后,即使该外部函数已经结束,但是内部函数引用的外部变量依然保存在内存中,我们把这些变量的集合称为闭包
      1. 如果引用闭包的函数是全局变量,闭包会一直存在,直到页面关闭
      2. 如果是局部变量引用闭包函数,那么等函数销毁,会执行垃圾回收
      3. 产生闭包的核心:
        1. 扫描内部函数,如果内部函数引用了外部变量
        2. 把内部变量引用的外部变量保存在堆中,变量在该外部执行上下文栈中
        3. 外部函数被销毁,但只是销毁了执行上下文,堆中的内存没有被回收
        4. 内部函数的调用又重新建立与堆数据连接
  5. 垃圾回收:
    1. 栈中:执行上下文执行结束后会自动销毁,向下移动ESP来销毁,也就是出栈
    2. 堆中:使用垃圾回收器(Chrome v8)
      1. 代际假说:
        1. 很多对象一经分配内存,很快就变得不可访问
        2. 不死的对象会活得更久
      2. 分代收集:新生代存放生存时间短的(1-8M),老生代存放生存时间久的对象
      3. 副回收器回收新生代垃圾,主回收器回收老生代垃圾
      4. 回收流程:标记->处理->整理
        1. 副垃圾回收器
          1. Scavenge算法(把新生代空间对半分,一半空闲区域,一半对象区域)
          2. 新加入的对象在对象区域,对象区域快写满时就执行一次垃圾清理操作
            1. 把存活的对象复制到空闲区域,然后清理对象区域,最后空闲区域和对象区域角色互转
            2. 如果两次翻转角色后,某一个对象还在的话,那么该对象移动到老生区
        2. 主垃圾回收器:对象占用空间大,对象存活时间长
          1. 标记-清除法
          2. 全停顿:一旦执行垃圾回收,javascript脚本会停止运行,待回收完毕后再恢复
          3. 增量标记算法:把垃圾回收拆分成小任务,使得小任务和js脚本交替运行,避免卡顿
      5. 避免内存泄漏方法:把临时用不到的变量设置为null,避免使用闭包

 

posted @ 2020-08-17 02:03  浪波激泥  阅读(154)  评论(0编辑  收藏  举报