We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
执行上下文,简单理解就是代码执行的环境。
在JS中,有三种执行上下文,分别是全局执行上下文、函数执行上下文,eval执行上下文(不作了解)。
首先要理解的是,JS的代码不是一行一行执行,而是一段一段的执行。每段也就是一个执行上下文。
每个上下文在开始执行前,都会做一个准备工作,这个工作有三个重要的属性,分别是:变量对象,作用域链,以及this。
变量对象是与执行上下文相关的数据作用域,保存了上下文中所有以var关键字声明的变量以及函数声明。
由于全局上下文与函数上下文中的变量对象不尽相同,所以下面分类讨论。
首先下结论,全局中的变量对象就是全局对象。
在客户端javaScript中,这个全局对象就是window。
全局对象是一个预定义的对象,保存了一堆预定义的属性和方法。
所有在全局上下文中以var关键字声明的变量以及函数声明都会保存在全局对象中。
全局对象是作用域链的顶层,
在函数执行上下文中,用活动对象代指变量对象。
这两个其实是一个东西,区别是变量对象我们是不可以直接访问的。
当进入一个执行上下文后,变量对象被激活,转换为活动对象,其上的属性和方法,我们才可以进行访问。
函数执行上下文中的活动对象通过函数的Arguments对象进行初始化。
执行上下文的代码分为两个阶段进行处理: 分析和执行,我们也可以叫做:
下面分析这两个过程中变量对象的情况。
激活变量对象,通过Arguments对象初始化活动对象(如果是函数执行上下文)
上下文中所有函数声明
上下文中所有以var关键字声明的变量
举个例子:
function foo(a){ var b = 2; function c(){}; var d = function(){}; b = 3; } foo(1);
进入执行上下文时,活动对象的情况如下:
AO = { arguments: { 0: 1, length: 1, }, a: 1, b: 2, c: reference to function c(){}, d: reference to FunctionExpression "d", }
在代码执行阶段,会顺序执行代码,变量对象会根据代码修改自己的值。
还是上面的例子,代码完毕,活动对象情况如下:
AO = { arguments: { 0: 1, length: 1, }, a: 1, b: undefined, c: reference to function c(){}, d: undefined, }
到此变量对象的整个创建过程就结束了,总结一下:
当想获取一个属性或方法时,会首先从当前上下文的变量对象中查找,如果没有,再去父级上下文的变量对象中查找,一直找到全局的变量对象,也就是全局对象。如果还找不到,就会报错。
这样多个变量对象组成的链表,我们称之为作用域链。
下面以一个函数的创建和调用两个时期,描述作用域链是如何变化的。
首先要知道的是,JS中采取的是词法作用域。
也就是说,在函数创建时,它所有的父级变量对象已经决定好了,这一点不会随着它调用的位置而发生改变。
在函数的内部,有个[[scope]]属性。在函数创建时,这个属性会保存所有父级变量对象组成的作用域。
注意:[[scope]]属性不代表完整的作用域链!
举个🌰 :
function foo() { function bar() { ... } }
函数创建时,各自的[[scope]]为:
foo.[[scope]] = [ globalContext.VO ] bar.[[scope]] = [ fooContext.AO, globalContext.VO, ]
函数调用,进入一个函数执行上下文,创建完变量对象后,会将变量对象添加到作用域链的前端。
Scope = [AO].concat([[scope]])
至此,作用域链创建完毕。
深入了解this
在我们写的代码中,会有不止一个函数,也就是说,会有很多个函数执行上下文被创建和执行。
为了统一管理执行上下文, JavaScript 引擎会创建一个执行上下文栈来统一进行管理。
执行上下文栈是一种先入后出的结构,下面简单阐述一下它的运行情况。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
执行上下文
执行上下文,简单理解就是代码执行的环境。
在JS中,有三种执行上下文,分别是全局执行上下文、函数执行上下文,eval执行上下文(不作了解)。
首先要理解的是,JS的代码不是一行一行执行,而是一段一段的执行。每段也就是一个执行上下文。
每个上下文在开始执行前,都会做一个准备工作,这个工作有三个重要的属性,分别是:变量对象,作用域链,以及this。
变量对象
变量对象是与执行上下文相关的数据作用域,保存了上下文中所有以var关键字声明的变量以及函数声明。
由于全局上下文与函数上下文中的变量对象不尽相同,所以下面分类讨论。
全局变量对象
首先下结论,全局中的变量对象就是全局对象。
在客户端javaScript中,这个全局对象就是window。
全局对象是一个预定义的对象,保存了一堆预定义的属性和方法。
所有在全局上下文中以var关键字声明的变量以及函数声明都会保存在全局对象中。
全局对象是作用域链的顶层,
函数变量对象
在函数执行上下文中,用活动对象代指变量对象。
这两个其实是一个东西,区别是变量对象我们是不可以直接访问的。
当进入一个执行上下文后,变量对象被激活,转换为活动对象,其上的属性和方法,我们才可以进行访问。
函数执行上下文中的活动对象通过函数的Arguments对象进行初始化。
执行过程
执行上下文的代码分为两个阶段进行处理: 分析和执行,我们也可以叫做:
下面分析这两个过程中变量对象的情况。
进入执行上下文
激活变量对象,通过Arguments对象初始化活动对象(如果是函数执行上下文)
上下文中所有函数声明
上下文中所有以var关键字声明的变量
举个例子:
进入执行上下文时,活动对象的情况如下:
执行代码
在代码执行阶段,会顺序执行代码,变量对象会根据代码修改自己的值。
还是上面的例子,代码完毕,活动对象情况如下:
到此变量对象的整个创建过程就结束了,总结一下:
作用域链
当想获取一个属性或方法时,会首先从当前上下文的变量对象中查找,如果没有,再去父级上下文的变量对象中查找,一直找到全局的变量对象,也就是全局对象。如果还找不到,就会报错。
这样多个变量对象组成的链表,我们称之为作用域链。
下面以一个函数的创建和调用两个时期,描述作用域链是如何变化的。
函数创建
首先要知道的是,JS中采取的是词法作用域。
也就是说,在函数创建时,它所有的父级变量对象已经决定好了,这一点不会随着它调用的位置而发生改变。
在函数的内部,有个[[scope]]属性。在函数创建时,这个属性会保存所有父级变量对象组成的作用域。
注意:[[scope]]属性不代表完整的作用域链!
举个🌰 :
函数创建时,各自的[[scope]]为:
函数调用
函数调用,进入一个函数执行上下文,创建完变量对象后,会将变量对象添加到作用域链的前端。
至此,作用域链创建完毕。
this
深入了解this
执行上下文栈
在我们写的代码中,会有不止一个函数,也就是说,会有很多个函数执行上下文被创建和执行。
为了统一管理执行上下文, JavaScript 引擎会创建一个执行上下文栈来统一进行管理。
执行上下文栈是一种先入后出的结构,下面简单阐述一下它的运行情况。
参考链接
JavaScript深入之词法作用域和动态作用域
JavaScript深入之执行上下文栈
JavaScript深入之变量对象
JavaScript深入之作用域链
JavaScript深入之执行上下文
The text was updated successfully, but these errors were encountered: