JavaScript作用域链使用介绍(2)

全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,因此所有全局变量和函数都是作为window对象的属性和放大创建的。每个函数都有自己的执行环境,当执行流进入一个函数的时候,函数的环境会被推入一个函数栈中,而在函数执行完毕后执行环境出栈并被销毁,保存在其中的所有变量和函数定义随之销毁,控制权返回到之前的执行环境中,全局的执行环境在应用程序退出(浏览器关闭)才会被销毁。

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain,不简称sc)来保证对执行环境有权访问的变量和函数的有序访问。作用域第一个对象始终是当前执行代码所在环境的变量对象(VO)

复制代码 代码如下:


function a(x,y){
            var b=x+y;
            return b;
        }

 

在函数a创建的时候它的作用域链填入全局对象,全局对象中有所有全局变量

image

如果执行环境是函数,那么将其活动对象(activation object, AO)作为作用域链第一个对象,第二个对象是包含环境,下一个是包含环境的包含环境。。。。。

复制代码 代码如下:


function a(x,y){
            var b=x+y;
            return b;
        }
        var tatal=a(5,10);


 这时候 var total=a(5,10);语句的作用域链如下

image

在函数运行过程中标识符的解析是沿着作用域链一级一级搜索的过程,从第一个对象开始,逐级向后回溯,直到找到同名标识符为止,找到后不再继续遍历,找不到就报错。

再来看看闭包

之前博客曾经总结道:只要存在调用内部函数的可能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,JavaScript的垃圾收集器才能释放相应的内存空间。回头再看看好理解了很多,父函数定义的变量在子函数的作用域链中,子函数没有被销毁,其作用域链中所有变量和函数就会被维护,不会被销毁。

复制代码 代码如下:


for(var i=0;i<elements.length;i++){
                elements[i].onclick=function(){
                    alert(i);
                }
            }


  这是上篇博客提到过的经典错误,每次element点击alert都是length,这段代码中为element绑定的click事件处理程序的作用域链是这样的

image

由于内部函数(click事件处理程序时刻有调用可能),所以其作用域链不能被销毁(更别说本例中i在全局作用域中,只能页面卸载是销毁),i的值一直保持for循环执行完后的length值,所以每次触发onclick的时候才会alert length。

复制代码 代码如下:


for(var i=0;i<elements.length;i++){
                (function(n){
                    elements[n].onclick=function(){
                        alert(n);
                    }
                })(i);
            }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdzxww.html