浅析JavaScript引擎的工作机制

JS引擎动态解析JavaScript的过程

1.语法检查阶段

       ①词法分析

               ②语法分析

2.运行阶段

                ①预解析阶段

                ②执行阶段

本文重点总结运行阶段JS引擎的工作机制

一、预解析阶段

首先创建执行上下文或者说创建执行上下文环境。创建的执行上下文包括:变量对象、作用域链、this三大部分

1.变量对象VO(variable object):包括变量声明、函数声明、arguments。下文中活动对象AO(action)也是变量对象的一种,只是相对于函数而言的,就是说调用函数之后,函数自己的变量对象就为活动对象。

2.作用域链(scope chain):变量对象以及所有父级作用域

3.this值:this值在进入上下文阶段就确定了,一旦进入执行阶段,this值就不会变了

变量对象 
作用域链 
this值 

之后会对变量对象VO/活动对象AO的一些属性填充值。此时上下文环境如下

 属性属性的值
 形参实参的值,未传递实参则为undefined
变量对象函数声明该函数的值
 变量声明undifined,注意!函数表达式在这里也理解为变量声明
作用域链  
this值  

以上所说的创建的执行上下文环境,是一个总结性的表述。

具体的是,JavaScript在执行一个代码段之前,会创建执行上下文。其中,这个代码段还分三种情况:全局代码、函数体、eval代码。其中eval代码不常用而且用后会有不必要的风险,本文不赘述。

对于全局代码,也就是说在全局环境下的代码,执行上下文环境中有

变量声明、函数表达式undefined
函数声明确定的值
thiswindow

对于函数体,也就是说在函数中,在创建的执行上下文环境中,除了以上数据(不包括this),以上数据由函数的[[scope]]属性复制而来,还会有参数、arguments等数据,

函数的执行上下文环境
[[scope]]除了this
this确定的值
形参确定的值
arguments确定的值

在函数中,作用域链是个指针,通过[[scope]]属性指向全局对象,由另一个链条指向内部变量,也就是下文说的活动对象

二、执行代码阶段

术语:在这里,为了区分,我们把函数内部定义的变量群体称为活动对象,把函数外部定义的变量群体称为变量对象。在上面我们把所有变量群体都称为变量对象

在进入执行代码阶段,预解析阶段所创建的三大部分的内容都可能会改变。当JavaScript引擎一行一行的执行代码时,会把遇到的三大部分的值重新赋予执行上下文环境,之前的值就会被覆盖

变量对象

对变量对象而言,假如变量是定义在函数内部的,而函数没有被调用,那他的值永远都是undefined

而函数被调用的情况下,这时候就会产生一个新的执行上下文环境,也产生了相应的作用域链,随之也有了执行上下文栈的概念。此时JS引擎会把产生的新的执行上下文环境压到之前的全局代码(相对而言,可以理解为父代码)所创建的执行上下文环境之上,像栈一样,当函数调用完成后,这个上下文环境便会消除,它里面的活动对象也被消除,此时全局(父)的执行上下文环境便又登上舞台。处于活动状态的执行上下文环境只能有一个,即栈最上方的一个。

作用域链

我们知道,在JavaScript中只有函数才能规定作用域。每个函数,在创建的时候(注意是创建而非执行),都有一个[[scope]]属性(一个指针),它包含了该函数作用域上层的所有变量对象,在执行阶段调用函数的时候,进入新的执行上下文环境,通过复制函数的[[scope]]属性中的对象,在加上函数本身的活动对象,便构建起执行环境的作用域链,该函数要访问栈下面他的父作用域的变量对象,就要通过这个[[scope]]属性。

补充一点,

在上面我们说到,每个函数在创建的时候,都有一个[[scope]]属性(一个指针),所以虽然是在调用阶段才复制[[scope]]属性创建作用域链,但其实作用域链中的变量对象在创建的时候就已经被决定了(调用的时候决定的是变量对象的值),也就是说,函数的作用域,是由创建时候的位置决定的,而不是由调用时候的位置决定的

具体代码如下

var a = 100;
function f1() {   //他的父作用域为全局,无论在哪里被调用
    console.log(a);
}
function f2() {
    var a = 200;
    f1();   //调用
}
f2();  //输出100,创建的位置决定了他的父作用域为全局,所以输出100

this值

重点谈下this值在不同环境下代表的对象

1.构造函数

如果把函数作为构造函数使用,那么构造函数中的this就代表他new出来的对象

2.函数作为对象的一个属性

那么函数中的this就指向该对象,这是比较常见的

3.函数用call、apply调用

那么函数中的this就指向传入这两种方法参数中的对象

4.普通函数

在全局环境下,this就指向window

5.DOM事件

在DOM事件中,this值就指向触发事件的DOM对象

以上只是最普通的JS引擎在运行阶段的解析机制,对于闭包,这些方面又有不同。

在闭包中,变量对象部分,还存在着对全局变量(严格来说是父级变量)的引用,而这些引用是通过作用域链存在的,所以在闭包中的函数,哪怕父级函数在执行完毕后,其活动对象也不会销毁,作用域链也依然存在,但是只有被闭包引用的活动对象不被销毁,其余的都会被内存回收。关于this的值,在闭包中,当函数作为对象的方法被调用时,若函数中有匿名函数,由于匿名函数的执行环境具有全局性,所以其this对象通常指向window。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值