JavaScript

JS的解析过程、作用域及作用域链、垃圾回收机制

字数:1856    阅读时间:10min
阅读量:687

JS是一门编译语言,是在浏览器运行时候开始编译的,浏览器是如何解析我们的 JS的呢?JS的解析过程可分为: 语法检查阶段执行阶段

  • 语法分析:
    • 词法分析:把js的字符流转换成标记流
    • 语法分析: 把标记流产生的记号按照ECMAScript标准生成语法树 (把收集到的信息存储到数据类型中)
  • 执行阶段:
    • 预解析:
      • 创建执行上下文;变量对象(变量声明,函数声明,参数),作用域链(变量对象以及所有父级作用域),this
      • 变量对象活动对象填充数值(权重:函数参数>函数声明>变量声明)
        • 函数参数:执行上下文变量对象的一个属性,属性名称是这个形参,值是实参的,没有传递参数值就是undefined
        • 函数声明:执行上下文变量对象的一个属性,属性名和属性值都是是函数对象创建出来的,如果变量对象已经包含了与他相同名字的属性,则会替换它的值
        • 变量声明:执行上下文变量对象的一个属性,属性名就是这个变量名,值是undefined,如果变量名和参数名函数声明名重复,则该声明会被忽略,但是其赋值操作不会被忽略
    • 执行阶段
      • 预解析之后就是js真正的执行阶段了,js引擎会一行一行读取运行代码,变量对象和活动对象都被赋予真是的值,如果函数没有被调用则里边的变量永远都是undefined

我们为了方便存储和读取数据,往往会将不同的数据存放在不同的地方,这些存放数据的地方就可以叫做作用域(作用域就是存储和读取的一套规则),JS中没有只有全局作用域和函数作用域(ES6才引入块级作用域)

  • 作用域
    • 创建: js采用的是静态作用域(词法作用域),也就是在词法分析的时候就把作用域确定好了,之后是不能改变的(evel()和with()可以改变但是消耗性能)
    • 特点:作用域可以嵌套但是不能重叠(重叠就覆盖)
    • 定义:是一种分类存储数据规则
  • 作用域链
    • 创建:作用域链是一个数组 [[Scope]] :[当前变量对象,父级上下文变量对象...];其中当前变量对象是在函数执行之前创建的,第二部分是在函数声明时就已经确定的
    • 特点:变量查找是只能一级一级向上找,不能向下找(子级能访问父级的变量,父级不能访问子级的变量)
    • 定义:是 一种变量查找的规则

垃圾回收机制:
  我们知道我们的浏览器内存是有限的,随着js中的变量、对象增多势必会对浏览器造成很大压力,那么我们就需要在使用完这些变量、对象之后就给他们清除掉;很幸运的是我们的JS有一套自己的垃圾回收机制,在我们不需要这些变量和对象的时候会自动帮我们清除他们。 JS中基础数据类型由于占内存小生命周期短,一般随着作用域移除的时候后会自动被清理,所以JS的垃圾回收主要是对堆中无用对象和无用数据结构的清除。JS垃圾回收方式大致分为引用计数法、 标记清除法:

  1. 引用计数法:每一个变量、对象都有一个引用计数,统计被多少个变量、对象引用;当引用计数为0的时候,就表明是一个无用变量、对象,就可以被回收;这种方式简单,但是有一个严重问题:无法处理循环引用问题;例如:两个对象互相引用,但是没有其他引用,本质上这两个对象应该就是无用对象,应该被清理,但是它们的引用计数都不为0,不会被清理;引用计数法是js最初开始时候采用的垃圾回收机制,在旧版ie浏览器可能会用到。
  2. 标记-清除法:从根对象开始遍历所有可达对象(被引用或使用),将他们标记为活动对象;在清除阶段,清除所有未被标记的对象;现代浏览器以标记清除法为主结合其他算法,如分代回收、增量标记等算法进行垃圾回收机制。 注:可达对象是指那些能够从根对象(如全局对象、当前执行上下文中的局部变量等)访问到的对象。换句话说,如果某个对象可以通过某条路径被访问到,那么它就是可达的。
  • 不会被清除的情况
    • 全局作用域变量:全局作用域的变量在浏览器打开的时候会一直被标记为"进入环境",只有在关闭浏览器的时候才会被标记为"离开环境"才能被清除;所以应该尽量减少定义全局变量或者使用严格模式
    • 闭包:当调用闭包的那个对象一直都没有被清除(比如在全局调用闭包,或者异步调用闭包的时候),那么闭包里的变量就一直存在不会被清除,做法是在调用完之后把调用闭包的那个对象给清空为'null'
    • 定时器和回调:没有清除定时器,那里边的变量就会一直存在不会被销毁;能清除的定时器一定要清除
    • Dom元素的引用:我们通常会将Dom引用放进一个数组或者对象中,当我们不需要这个对象了把这个对象删除了,但是这个对象的引用还是依然存在的,这个时候就需要手动将这个Dom的引用删除:整个对象为'null'或者删除这个属性
野生小园猿
励志做一只遨游在知识海洋里的小白鲨
查看“野生小园猿”的所有文章 →

相关推荐