JavaScript作用域和执行环境
2016-03-27 14:17
603 查看
参考文章:
/article/1308011.html(不得不说汤姆大叔这几篇确实是好文呐!但是要数清晰程度下面这一个更加清晰明了
/article/1307616.html)
还有知乎上的一篇解读:http://www.zhihu.com/question/36393048
/article/4780185.html
http://www.codeweblog.com/javascript-%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE%E8%A7%A3%E6%9E%90/
http://blog.sina.com.cn/s/blog_5d64f7e3010172mk.html
http://blog.sina.com.cn/s/blog_5d64f7e3010172mk.html
每个函数都有自己的执行环境,执行到函数B,就会创建新的执行环境B,然后压入栈内,当函数B执行完,则执行环境从栈内弹出,将控制权返回到之前的执行环境。
如果把全局的执行环境看做一个对象的话,那么这个全局的执行环境是这样的,包含三个部分:指针,变量对象,作用域链。
实际上,执行环境都会关联一个变量对象和作用域链
变量对象(Variable Object)是一个与执行环境相关的特殊对象,它存储在执行环境中声明的以下内容:
变量 : (var ,变量声明);
函数声明 : (FunctionDeclaration,缩写为FD);
函数的形参
作用域链稍后会讲到。
该全局执行环境有一个变量对象(variable object),特殊地是,由于这个变量对象属于全局执行环境,因此该变量对象是全局的。
看上面这段代码:
在运行浏览器的时候,对应的全局变量对象是这个:
那这时候全局执行环境的作用域呢?当然只有Global Variable Object可以被访问,因为outFun创建的变量对象
即
当然了,outFun这个函数在创建的同时,有没有创建新的执行环境呢?当然没有!记住,执行环境只有在函数调用或执行的时候才会创建,并压入堆栈。也就是说到创建outFun这一步还在全局的执行环境中。
但是,outFun函数在创建的时候,却搞到了自己的变量对象,恩对,没错,创建即拥有自己的一块地盘,并且拥有自己的作用域链。当在outFun找不到要访问的变量的时候,就会往“父级”作用域中找,也就是说优先在当前变量对象中寻找。
这时候outFun的变量对象和作用域链为:
好了,继续往下走,调用outFun,返回值赋给globalVar,记住,从执行环境开始分析,然后深入VO和Scope chain
那么我刚刚提到了“调用outFun”,也就是说函数被调用了,开始创建新的执行环境,暂且命名为执行环境C,在执行环境C中,我们开始跑outFun函数里面的内容,此时我们应该分析什么?当然还是VO和Scope chain了。这时候outFun 的 VO要进化了,为什么呢,因为开始调用outFun VO里面的内容了,所以VO开始干活了,以前没有调用它的时候处于闲置状态,现在处于活动状态,而且还加了一个新的属性argument,所以要改名字了。我们称之为“Active
Object”,简称AO。恩,然后在新的执行环境C中outFun开始基于AO和scope chain(上面已经叙述过outFun的scope chain)干活。干完活之后结束执行环境C,顺便返回了一个内部对象innerFun的引用给了全局变量globalVar,然后顺利带着战利品回到全局的执行环境。
在执行环境C中,outFunAO为,然后进行outFun中的操作
那么,这一步结束之后,global VO有没有变化?
当然!global VO里面的globalVar之前只是声明在那里了,可还没赋值呢,所以到了这一步(赋值这一步),global VO变成下面这个(实际上就是global的值变了,也没啥)
好了,赋值完毕!到下一步,但是这里要提一件事情,就是outFun虽然结束了,但是它在内部创建了一个闭包(返回了一个内部函数),这个内部函数是可以访问outFun的成员数学i的!但是outFun要销毁啊,这咋办,所以呢,又创建了一个闭包专门代替outFun的工作,见下图(来自http://www.codeweblog.com/javascript-%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE%E8%A7%A3%E6%9E%90/),assignEvent是这个链接里面举得例子,在我这里把它换成outFun()就可以了。
然后到了最后一步,调用globalVar,这时候创建新的执行环境D,执行环境D中VO为
以上说的可能有点乱,下面总结一下:
1、浏览器对象是一个大的执行环境——全局执行环境,每个函数在调用的时候都会创建新的执行环境,并入栈,执行完毕,出栈销毁
2、每个执行环境都会关联一个变量对象,用于存储局部变量、内部函数,每个执行环境同样有一条作用域链,这条作用域链由嵌套深度决定,优先查询当前执行环境下的变量对象,找不到,沿着作用域链往下找,一直到全局变量对象。
3、每调用一个函数,都创建新的执行环境,同时,该函数关联的变量对象激活,添加argument等属性转为活动对象,直到执行环境结束,然后销毁但是,如果创建了闭包,则会存在于内存中,因为还有活要干
/article/1308011.html(不得不说汤姆大叔这几篇确实是好文呐!但是要数清晰程度下面这一个更加清晰明了
/article/1307616.html)
还有知乎上的一篇解读:http://www.zhihu.com/question/36393048
/article/4780185.html
http://www.codeweblog.com/javascript-%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE%E8%A7%A3%E6%9E%90/
http://blog.sina.com.cn/s/blog_5d64f7e3010172mk.html
http://blog.sina.com.cn/s/blog_5d64f7e3010172mk.html
以下内容均在对上述的参考文章理解的基础上撰写
打开浏览器,就会创建全局执行环境Global Execute Context,一直到关闭应用(也就是关闭浏览器)为止,全局的执行环境才会被销毁。每个函数都有自己的执行环境,执行到函数B,就会创建新的执行环境B,然后压入栈内,当函数B执行完,则执行环境从栈内弹出,将控制权返回到之前的执行环境。
如果把全局的执行环境看做一个对象的话,那么这个全局的执行环境是这样的,包含三个部分:指针,变量对象,作用域链。
<span style="font-size:18px;">globalExecutionContext { this : 指向全局对象 globalVaribleObject : 全局的变量对象 scopeChain : 该全局执行环境的作用域链 }</span>
实际上,执行环境都会关联一个变量对象和作用域链
变量对象(Variable Object)是一个与执行环境相关的特殊对象,它存储在执行环境中声明的以下内容:
变量 : (var ,变量声明);
函数声明 : (FunctionDeclaration,缩写为FD);
函数的形参
作用域链稍后会讲到。
该全局执行环境有一个变量对象(variable object),特殊地是,由于这个变量对象属于全局执行环境,因此该变量对象是全局的。
<span style="font-size:18px;"><pre name="code" class="javascript"> var globalVar; //创建函数 function outFun() { var i = 0; function innerFun() { i++; document.write(i); } return innerFun; } globalVar = outFun();//调用outFun函数,返回内部函数 globalVar();//调用内部函数,访问内部变量</span>
看上面这段代码:
在运行浏览器的时候,对应的全局变量对象是这个:
<span style="font-size:18px;">globalVO: { global : undefined, outFun : function reference (闲置状态中) }</span>
那这时候全局执行环境的作用域呢?当然只有Global Variable Object可以被访问,因为outFun创建的变量对象
即
<span style="font-size:18px;">scopeChain: { 0 => globalVO }</span>
当然了,outFun这个函数在创建的同时,有没有创建新的执行环境呢?当然没有!记住,执行环境只有在函数调用或执行的时候才会创建,并压入堆栈。也就是说到创建outFun这一步还在全局的执行环境中。
但是,outFun函数在创建的时候,却搞到了自己的变量对象,恩对,没错,创建即拥有自己的一块地盘,并且拥有自己的作用域链。当在outFun找不到要访问的变量的时候,就会往“父级”作用域中找,也就是说优先在当前变量对象中寻找。
这时候outFun的变量对象和作用域链为:
<span style="font-size:18px;">Vo: { i : undefined;//因为outFun还没运行,所以仅仅是声明在这,而并没有开始赋值 innerFun : function reference } scope chain: { 0 => outFunAO (当前执行环境下的活动对象AO就是它) 1 => globalVO }</span>
好了,继续往下走,调用outFun,返回值赋给globalVar,记住,从执行环境开始分析,然后深入VO和Scope chain
那么我刚刚提到了“调用outFun”,也就是说函数被调用了,开始创建新的执行环境,暂且命名为执行环境C,在执行环境C中,我们开始跑outFun函数里面的内容,此时我们应该分析什么?当然还是VO和Scope chain了。这时候outFun 的 VO要进化了,为什么呢,因为开始调用outFun VO里面的内容了,所以VO开始干活了,以前没有调用它的时候处于闲置状态,现在处于活动状态,而且还加了一个新的属性argument,所以要改名字了。我们称之为“Active
Object”,简称AO。恩,然后在新的执行环境C中outFun开始基于AO和scope chain(上面已经叙述过outFun的scope chain)干活。干完活之后结束执行环境C,顺便返回了一个内部对象innerFun的引用给了全局变量globalVar,然后顺利带着战利品回到全局的执行环境。
在执行环境C中,outFunAO为,然后进行outFun中的操作
<span style="font-size:18px;">outFun AO: { argument :undefined,//这里由于没有参数传入,所以为undefined,但是,argument其实是一个数组[] i : undefined, innerFun : function reference }</span>
那么,这一步结束之后,global VO有没有变化?
当然!global VO里面的globalVar之前只是声明在那里了,可还没赋值呢,所以到了这一步(赋值这一步),global VO变成下面这个(实际上就是global的值变了,也没啥)
globalVO: { global : function reference to innerFun, outFun : function reference } scope chain: { 0 => outFun Vo 1 => global VO }
好了,赋值完毕!到下一步,但是这里要提一件事情,就是outFun虽然结束了,但是它在内部创建了一个闭包(返回了一个内部函数),这个内部函数是可以访问outFun的成员数学i的!但是outFun要销毁啊,这咋办,所以呢,又创建了一个闭包专门代替outFun的工作,见下图(来自http://www.codeweblog.com/javascript-%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE%E8%A7%A3%E6%9E%90/),assignEvent是这个链接里面举得例子,在我这里把它换成outFun()就可以了。
然后到了最后一步,调用globalVar,这时候创建新的执行环境D,执行环境D中VO为
innerVO: { argument : undefined,//和之前一样,实际上argument是一个数组 } scopeChain: { 0 => innerVO 1 => outFunVO 2 => globalVO }
以上说的可能有点乱,下面总结一下:
1、浏览器对象是一个大的执行环境——全局执行环境,每个函数在调用的时候都会创建新的执行环境,并入栈,执行完毕,出栈销毁
2、每个执行环境都会关联一个变量对象,用于存储局部变量、内部函数,每个执行环境同样有一条作用域链,这条作用域链由嵌套深度决定,优先查询当前执行环境下的变量对象,找不到,沿着作用域链往下找,一直到全局变量对象。
3、每调用一个函数,都创建新的执行环境,同时,该函数关联的变量对象激活,添加argument等属性转为活动对象,直到执行环境结束,然后销毁但是,如果创建了闭包,则会存在于内存中,因为还有活要干
相关文章推荐
- JSP中重写404,相关配置
- Javascript的console.log()用法
- javascript学习笔记 - 执行环境及作用域
- 第五天学习javascript
- 在JavaScript中创建命名空间的几种写法
- 改变字体大小实现自适应之js方案A
- jsp
- JavaScript基础回顾(思维导图之JavaScript变量)
- JavaScript判断手机号运营商是移动、联通、电信还是其他(代码简单
- 基于JSP Servlet xml的select二级联动
- 怎样克服 JavaScript 框架疲劳?
- [笔记] PhantomJS爬虫小记
- 日常js函数积累
- JavaScript 闭包
- ExtJs学习基础知识
- JSP编译成Servlet(五)JDT Compiler编译器
- JSP编译成Servlet(五)JDT Compiler编译器
- js中的null和undefined
- JavaScript 惰性载入函数
- JavaScript中this详解