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
javascript运行的代码环境有三种:
全局上下文是最外围的一个执行环境,web浏览器中被认为是window对象。在初始化代码时会先进入全局上下文中,每当一个函数被调用时就会为该函数创建一个执行上下文,每个函数都有自己的执行上下文。来看一段代码:
function f1() { var f1Context = 'f1 context'; function f2() { var f2Context = 'f2 context'; function f3() { var f3Context = 'f3 context'; console.log(f3Context); } f3(); console.log(f2Context); } f2(); console.log(f1Context); } f1();
这段代码有4个执行上下文:全局上下文和f1(),f2(),f3()属于自己的执行上下文。
全局上下文拥有变量f1(),f1()的上下文中有变量f1Context和f2(),f2()的上下文有变量f2Context和f3(),f3()上下文有变量f3Context。
在这我们了解下执行环境栈ECS,一段代码所有的执行上下文都会被推入栈中等待被执行,因为js是单线程,任务都为同步任务的情况下某一时间只能执行一个任务,执行一段代码首先会进入全局上下文中,并将其压入ECS中,执行f1()会为其创建执行上下文压入栈顶,f1()中有f2(),再为f2()创建f2()的执行上下文,依次,最终全局上下文被压入到栈底,f3()的执行上下文在栈顶,函数执行完后,ECS就会弹出其上下文,f3()上下文弹出后,f2()上下文来到栈顶,开始执行f2(),依次,最后ECS中只剩下全局上下文,它等到应用程序退出,例如浏览器关闭时销毁。
总结:(执行上下文就用EC替代)
1. 全局上下文压入栈顶 2. 执行某一函数就为其创建一个EC,并压入栈顶 3. 栈顶的函数执行完之后它的EC就会从ECS中弹出,并且变量对象(VO)随之销毁 4. 所有函数执行完之后ECS中只剩下全局上下文,在应用关闭时销毁
大家再看一道道题:
function foo(i) { if(i == 3) { return; } foo(i+1); console.log(i); } foo(0);
大家明白执行上下文的进栈出栈就应该知道结果为什么是2,1,0
ECS栈顶为foo(3)的的上下文,直接return弹出后,栈顶变成foo(2)的上下文,执行foo(2),输出2并弹出,执行foo(1),输出1并弹出,执行foo(0),输出0并弹出,关闭浏览器后全局EC弹出,所以结果为2,1,0
刚才提到VO,我们来了解什么是VO
创建执行上下文时与之关联的会有一个变量对象,该上下文中的所有变量和函数全都保存在这个对象中。
进入到一个执行上下文时,此执行上下文中的变量和函数都可以被访问到,可以理解为被激活
谈到了上下文的创建和执行,我们来看看EC建立的过程:
建立阶段:(函数被调用,但是还未执行函数中的代码) 1. 创建变量,参数,函数,arguments对象 2. 建立作用域链 3. 确定this的值 执行阶段:变量赋值,函数引用,执行代码
执行上下文为一个对象,包含VO,作用域链和this
executionContextObj = { variableObject: { /* 函数中的arguments对象, 参数, 内部的变量以及函数声明 */ }, scopeChain: { /* variableObject 以及所有父执行上下文中的variableObject */ }, this: {} }
具体过程:
1. 找到当前上下文调用函数的代码 2. 执行代码之前,先创建执行上下文 3. 创建阶段: 3-1. 创建变量对象(VO): 1. 创建arguments对象,检查当前上下文的参数,建立该对象下的属性和属性值 2. 扫描上下文的函数申明: 1. 每扫描到一个函数什么就会在VO里面用函数名创建一个属性, 为一个指针,指向该函数在内存中的地址 2. 如果函数名在VO中已经存在,对应的属性值会被新的引用覆盖 3. 扫描上下文的变量申明: 1. 每扫描到一个变量就会用变量名作为属性名,其值初始化为undefined 2. 如果该变量名在VO中已经存在,则直接跳过继续扫描 3-2. 初始化作用域链 3-3. 确定上下文中this的指向 4. 代码执行阶段 4-1. 执行函数体中的代码,给VO中的变量赋值
看代码理解:
function foo(i) { var a = 'hello'; var b = function privateB() {}; function c() {} } foo(22);
调用foo(22)时创建上下文包括VO,作用域链,this值
以函数名作为属性值,指向该函数在内存中的地址;变量名作为属性名,其初始化值为undefined
注意:函数申明先于变量申明
fooExecutionContext = { variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c(), a: undefined, b: undefined }, scopeChain: { ... }, this: { ... } }
创建阶段结束后就会进入代码执行阶段,给VO中的变量赋值
fooExecutionContext = { variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c(), a: 'hello', b: pointer to function privateB() }, scopeChain: { ... }, this: { ... } }
function foo() { console.log(f1); //f1() {} console.log(f2); //undefined var f1 = 'hosting'; var f2 = function() {} function f1() {} } foo();
调用foo()时会创建VO,初始VO中变量值等有一系列的过程,所有变量初始化值为undefined,所以console.log(f2)的值为undefined。并且函数申明先于变量申明,所以console.log(f1)的值为f1()函数而不为hosting
1. 调用函数时会为其创建执行上下文,并压入执行环境栈的栈顶,执行完毕 弹出,执行上下文被销毁,随之VO也被销毁 2. EC创建阶段分创建阶段和代码执行阶段 3. 创建阶段初始变量值为undefined,执行阶段才为变量赋值 4. 函数申明先于变量申明
上一篇:深入javascript之作用域 下一篇:深入javascript之闭包
参考:Execution Context
The text was updated successfully, but these errors were encountered:
No branches or pull requests
一,相关概念
二,执行上下文
javascript运行的代码环境有三种:
全局上下文是最外围的一个执行环境,web浏览器中被认为是window对象。在初始化代码时会先进入全局上下文中,每当一个函数被调用时就会为该函数创建一个执行上下文,每个函数都有自己的执行上下文。来看一段代码:
这段代码有4个执行上下文:全局上下文和f1(),f2(),f3()属于自己的执行上下文。
全局上下文拥有变量f1(),f1()的上下文中有变量f1Context和f2(),f2()的上下文有变量f2Context和f3(),f3()上下文有变量f3Context。
在这我们了解下执行环境栈ECS,一段代码所有的执行上下文都会被推入栈中等待被执行,因为js是单线程,任务都为同步任务的情况下某一时间只能执行一个任务,执行一段代码首先会进入全局上下文中,并将其压入ECS中,执行f1()会为其创建执行上下文压入栈顶,f1()中有f2(),再为f2()创建f2()的执行上下文,依次,最终全局上下文被压入到栈底,f3()的执行上下文在栈顶,函数执行完后,ECS就会弹出其上下文,f3()上下文弹出后,f2()上下文来到栈顶,开始执行f2(),依次,最后ECS中只剩下全局上下文,它等到应用程序退出,例如浏览器关闭时销毁。
总结:(执行上下文就用EC替代)
大家再看一道道题:
大家明白执行上下文的进栈出栈就应该知道结果为什么是2,1,0
ECS栈顶为foo(3)的的上下文,直接return弹出后,栈顶变成foo(2)的上下文,执行foo(2),输出2并弹出,执行foo(1),输出1并弹出,执行foo(0),输出0并弹出,关闭浏览器后全局EC弹出,所以结果为2,1,0
刚才提到VO,我们来了解什么是VO
三,VO/AO
VO(变量对象)
AO(活动对象)
谈到了上下文的创建和执行,我们来看看EC建立的过程:
执行上下文为一个对象,包含VO,作用域链和this
具体过程:
看代码理解:
调用foo(22)时创建上下文包括VO,作用域链,this值
以函数名作为属性值,指向该函数在内存中的地址;变量名作为属性名,其初始化值为undefined
注意:函数申明先于变量申明
创建阶段结束后就会进入代码执行阶段,给VO中的变量赋值
四,变量提升
调用foo()时会创建VO,初始VO中变量值等有一系列的过程,所有变量初始化值为undefined,所以console.log(f2)的值为undefined。并且函数申明先于变量申明,所以console.log(f1)的值为f1()函数而不为hosting
五,总结
上一篇:深入javascript之作用域
下一篇:深入javascript之闭包
参考:Execution Context
The text was updated successfully, but these errors were encountered: