本文章记录本人在深入学习执行上下文以及作用域链中看书理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。
执行上下文概念
执行上下文,是ECMAScript
规法中用来描述js
代码执行的抽象概念。所有的js
代码都是在某个执行上下文运行的。在一个执行上下文中调用一个函数,会进入一个新的执行上下文。调用结束就回到原来的执行上下文中。在函数调用的过程中,如果调用了其他的函数,那么将进入一个新的执行上下文,就会形成一个执行上下文栈。
每个执行上下文都与一个作用域链关联在一起。该作用域链用来在函数执行时求出标识符的值。作用域链中包含许多的对象,在标识符进行求值的时候,先从链首开始,接着依次查找后面的对象,直到某个对象中的标示符名称相等的属性。
执行上下文顺序
在进入执行上下文时候,会按照顺序执行下面的操作:
创建激活对象
激活对象是在进入执行上下文时候创建出来的,并且与新的执行上下文关联在一起。在初始化构造函数的时候,该对象包含一个arguments
属性。激活对象在变量初始化也会用到。创建作用域链
每一个函数都有一个内部属性[[scope]]
,它的值是一个包含多个对象的链。这个属性的具体指与函数的创建方式和代码中的位置有很大的关系。这一步的操作是把上一步创建的激活对象添加到函数的[[scope]]
属性对应的链的前面。变量初始化
对函数中需要用到的变量进行初始化。初始化时使用到的对象是前面创建的激活对象,不过这个时还不能称作为变量对象。函数的实际参数、内部函数的局部变量是会被初始化的。局部变量是在变量对象创建的过程中创建了同名的属性,这个属性值为undefined
,在函数执行的过程中才会被真正的赋值。
函数上下文环境
函数总是在自己的执行上下文环境中运行,例如读/写局部变量、函数参数,以及运行内部逻辑结构等等。创建上下文环境的过程中,js
会遵守下面的规则:
- 根据调用时传递的参数创建调用对象。
- 创建参数对象,存储参数变量。
- 创建对象属性,存储函数定义的布局变量。
- 把调用对象放在作用域链的头部,方便检索。
- 执行函数结构体的代码。
- 返回函数的返回值。
作用域
js
中作用域又分为词法作用域(定义作用域)和动态作用域。在函数还没调用之前,根据函数结构的嵌套关系来确定函数的作用域。因此作用域取决于源代码,通常编译器可以进行静态的分析来确定标示符的引用。
动态作用域
动态作用域(定义作用域),当函数被调用之后,其作用域会因为调用而发生变化,此时作用域链也会随之调整。
词法作用域(定义作用域)
词法作用域(定义作用域)用来说明函数定义是存在的嵌套关系。当函数被执行的时候,作用域可能发生变化。js
函数运行在它们的作用域中,而不是它们执行的作用域。
3种创建函数的作用域
创建函数有3种方法,分别是:function
函数声明,function
表达式和使用function
构造器函数。使用不同的创建函数的方式,所scope
属性也会有所不同,从而影响函数执行过程中的作用域链。
- 使用函数声明的函数对象是在进入执行上下文的时候变量初始化的过程中创建的。该对象的
scope
属性的值是它被创建时的执行上下文对应的作用域链。 - 使用函数表达式的函数对象是在该表达式被执行的时候创建的。该对象的
scope
属性的值与使用函数声明创建的对象一样。 - 使用函数构造器的声明一个函数通常有两种方式,常用的就是
var funcName = new Function(x1, x2, ... xn)
,其中x1,x2 ..., xn
表示的是该函数的形参,使用该方式的函数对象是在构造器调用的时候创建的。该对象的scope
属性的值一直是一个只包含全局对象的作用域链。
最后,如果文章有什么错误和疑问的地方,请指出。与sf各位共勉!目前是未完待续!!!